<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>

<HEAD>
    <TITLE>Lua 5.4 参考手册</TITLE>
    <LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
    <LINK REL="stylesheet" TYPE="text/css" HREF="manual.css">
    <!-- <META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1"> -->
</HEAD>

<BODY>
    <H1>
        <A HREF="http://www.Lua.org/"><IMG SRC="logo.gif" ALT="Lua "></A>
        Lua 5.4 参考手册
    </H1>

    <p />
    作者: Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

    <p />
    <SMALL>
        版权所有 &copy; 2020&ndash;2023 Lua .org, PUC-Rio.通过
        <A HREF="http://www.Lua.org/license.html">Lua license</A>的条款免费提供.
    </SMALL>

    <p />
    <DIV CLASS="menubar">
        <A HREF="contents.html#contents">目录</A>
        &middot;
        <A HREF="contents.html#index">索引</A>
        &middot;
        <A HREF="http://www.Lua.org/manual/">其它版本</A>
    </DIV>

    <h1>1 &ndash; <a name="1">简介</a></h1>

    <p />
    Lua 是一种强大、高效、轻量级、可嵌入的脚本语言。
    它支持过程式编程、面向对象编程、函数式编程、数据驱动编程和数据描述。

    <p />
    Lua 融合了简单的过程语法和基于关联数组及可扩展语义的强大数据描述结构。
    Lua 是动态类型的，通过基于寄存器的虚拟机解释字节码运行，并配有分代式垃圾回收的自动内存管理，使其适用于配置、脚本编写和快速原型制作。

    <p />
    Lua 作为库实现，使用 <em>clean C(纯C)</em>(标准的 C 和 C++ 的公共子集)编写。
    Lua 发布版包含一个名为 <code>lua</code> 的宿主程序，该程序使用 Lua 库提供一个完整的、独立的 Lua 解释器，用于批处理交互。
    Lua 旨在既作为需要它的程序中一个强大的、轻量级的的嵌入式的脚本语言，也可以作为一个强大但轻量级且高效的独立语言。

    <p />
    作为扩展语言，Lua 没有 "main" 程序的概念：
    它被<em>嵌入</em>在宿主程序中工作，该宿主程序称为 <em>被嵌入程序</em> 或简称为 <em>宿主</em>(通常，这个宿主是独立的 `lua` 程序)。
    宿主程序可以调用函数来执行 Lua 代码片段，可以读写 Lua 变量，也可以注册 C 函数以供 Lua 代码调用。
    通过使用 C 函数，可以增强 Lua 以应对各种不同的领域，从而成为共享语法框架的定制编程语言。

    <p />
    Lua 是一个免费软件，其使用许可证决定了它的使用过程无需任何担保。
    本手册所描述的实现可以在 Lua 的官方网站 <code>www.Lua.org</code> 找到。

    <p />
    与其它的许多参考手册一样，这份文档有些地方比较枯燥。
    关于 Lua 背后的设计思想，
    可以看看 Lua 网站上提供的技术论文。
    至于用 Lua 编程的细节介绍，
    请参阅 Roberto 的书，<em>Programming in Lua</em>。

    <h1>2 &ndash; <a name="2">基本概念</a></h1>

    <p />
    本章描述了语言的基本概念。

    <h2>2.1 &ndash; <a name="2.1">值与类型</a></h2>

    <p />
    Lua 是一门动态类型的语言。
    这意味着变量没有类型，只有值有类型。
    语言中没有类型定义。
    所有值都有它们自己的类型。

    <p />
    Lua 中的所有值都是第一类(first-class)值。
    这意味着所有的值都能保存在变量里、作为参数传递到其它函数、以及作为返回值。

    <p />
    Lua 中有 8 种基础类型：
    <em>nil</em>, <em>boolean</em>, <em>number</em>,
    <em>string</em>, <em>function</em>, <em>userdata</em>,
    <em>thread</em> 和 <em>table</em>。

    <em>nil</em> 类型只有一个值，即 <b>nil</b>，其主要特性是区别其它任何值；它通常代表有用值的缺失状态。
    <em>boolean</em> 类型有两个值，<b>false</b> 和 <b>true</b>。<b>nil</b> 和 <b>false</b> 会使条件为假；它们被统称为 <em>假值</em>。任何其它值都会使条件为真。
    尽管有其名称，但 <b>false</b> 经常被用作 <b>nil</b> 的替代品，关键区别在于 <b>false</b> 在表中表现为一个常规值，而表中的 <b>nil</b> 代表一个缺失的键。

    <p />
    <em>number</em> 类型有两种子类型 (<em>integer</em> 和 <em>float</em>) 以表示一个整数或一个实(浮点)数。
    标准 Lua 使用64位整数和双精度(64位)浮点数，但你可以编译Lua以使用32位整数 和/或 32位浮点数。
    这种选项对于小型机器和嵌入式系统是值得考虑的。(参见文件 <code>luaconf.h</code> 中的宏 <code>lua_32BITS</code>)

    <p />
    除非另有说明，否则在操作整数时，所有的溢出都会根据二进制补码算法的通常规则进行"回绕"。
    (换句话说，真实结果是可表示的唯一整数，它等于数学结果与 <em>2<sup>n</sup></em> 的模，其中 <em>n</em> 是整数类型中的位数)

    <p />
    Lua 对于何时使用每个子类型有明确的规则，
    但它也会根据需要在它们之间自动转换(参见 <a href="#3.4.3">&sect;3.4.3</a>)。
    因此，程序员可以选择忽略整数和浮点数之间的不同或者假定对每个数的表示形式有完整的控制权。

    <p />
    <em>string</em> 类型表示一个不可变的字节序列。
    字符串(string)可以包含任何8位值，
    包括零('<code>\0</code>')。
    Lua 中的字符串与编码无关；它不关心字符串中的具体内容。
    Lua 中的字符串长度必须能够使用 Lua 整数表示。

    <p />
    Lua 能调用(和操作)用 Lua 或 C (参见<a href="#3.4.10">&sect;3.4.10</a>) 编写的函数。
    它们都通过 <em>function</em> 类型表示。

    <p />
    <em>userdata</em> 类型允许将 C 中的数据保存在 Lua 变量中。
    用户数据(userdata)的值表示一个块内存。
    有两种类型：<em>完全用户数据</em> 和 <em>轻量级用户数据</em>。
    完全用户数据(full userdata)是一块由 Lua 管理的内存对应的对象。
    轻量级用户数据(light userdata)是一个简单的 C 指针值。

    Userdata 在 Lua 中除了赋值和相等性判断外没有其它预定义操作。
    通过使用<em>元表(metatable)</em>，程序员可以为完全用户数据定义操作(参见 <a href="#2.4">&sect;2.4</a>)。
    你只能通过 C API 而无法在 Lua 代码中创建或者修改用户数据的值，这保证了数据完全被宿主程序所掌控。

    <p />
    thread 类型表示了一个独立的执行线程，被用于实现协程(参见 <a href="#2.6">&sect;2.6</a>)。
    Lua 的线程与操作系统的线程毫无关系。
    Lua 为所有的系统，包括那些不支持原生线程的系统，提供了协程支持。

    <p />
    <em>table</em> 类型实现了关联数组，
    也就是说，索引不仅可以是数字，也可以是除 <b>nil</b> 和 <em>NaN</em>
    (<em>Not a Number</em> 是 IEEE 754 标准使用的特殊浮点数，用于表示如 0/0 等未定义的数值结果)以外的任何 Lua 值。
    表可以是 <em>异构</em> 的；也就是说，它们可以包含各种类型(除了 <b>nil</b>)的值。与该表相关的值为 <b>nil</b> 的键都不算该表的组成部分。
    反过来说，任何不属于表的键都与一个值 <b>nil</b> 关联。

    <p />
    表是 Lua 中唯一的数据结构；
    它们可以用来表示一个数组(array)、列表(list)、符号表(symbol table)、集合(set)、记录(record)、图(graph)、树(tree)、等等。
    表示记录时，Lua 使用字段名作为索引。
    Lua 提供 <code>a.name</code> 作为语法糖来表示 <code>a["name"]</code>。
    Lua 提供了多种方便的方法以创建表(参见 <a href="#3.4.9">&sect;3.4.9</a>)。

    <p />
    类似于索引，表字段的值可以是任何类型，特别指出，因为函数也是第一类值，表的字段也可以是一个函数。
    表也能携带 <em>函数</em> (参见 <a href="#3.4.11">&sect;3.4.11</a>)。

    <p />
    表的索引遵循 Lua 的原始相等性规则。
    当且仅当 <code>i</code> 和 <code>j</code> 是原始等价(不使用元方法的等价)时，表达式 <code>a[i]</code> 和
    <code>a[j]</code> 表示表中相同的元素。
    特别指出：带有整数值的浮点数和它们各组的整数相等(例如：<code>1.0 == 1</code>)。
    为了避免歧义，任何等于一个整数的浮点数作为索引时都被转换为整数。
    例如：如果你写 <code>a[2.0] = true</code>,
    实际插入到表中的键将是整数 <code>2</code>。

    <p />
    表、函数、线程和(完整的)用户数据值都是<em>对象</em>：
    变量实际上不包含这些值，而是对它们的<em>引用</em>。
    赋值，参数传递和函数返回总是操作这些值的引用，这些操作不会隐式地进行复制。

    <p />
    库函数 <a href="#pdf-type"><code>type</code></a> 返回一个描述给定值类型的字符串。

    <h2>2.2 &ndash; <a name="2.2">环境与全局环境</a></h2>

    <p />
    如我们在 <a href="#3.2">&sect;3.2</a> 和 <a href="#3.3.3">&sect;3.3.3</a>进一步讨论的，
    任何自由名称(即没有被任何声明绑定) <code>var</code>
    都被语法翻译成 <code>_ENV.var</code>。
    此外，每个块都被编译在一个外部局部变量 <code>_ENV</code>(参见 <a href="#3.3.2">&sect;3.3.2</a>)的作用域中。
    因此<code>_ENV</code>在程序块中永远不会是一个自由名称。

    <p />
    尽管存在外部 <code>_ENV</code> 变量和自由名称的翻译，<code>_ENV</code>也是一个完全合法的名称。
    特别地，你能使用这个名字来定义一个新的变量和参数。
    每个对自由名的引用都使用在程序中可见的 <code>_ENV</code>，遵循 Lua 的通常可见性规则(参见 <a href="#3.5"> 第3.5节</a>)。

    <p />
    任何用作 <code>_ENV</code> 值的表都叫做 <em>环境</em>。

    <p />
    Lua 保留了一个叫做 <em>全局环境</em> 的特殊环境。
    这个值保存在 C 注册表的一个特殊索引中(参见 <a href="#4.3">&sect;4.3</a>)。
    在 Lua 中，全局变量 _G 初始化为这个值(_G 在内部永远不会使用，所以更改它的值只会对你的代码产生影响)。

    <p />
    当 Lua 加载一个程序块时，它的 <code>_ENV</code> 变量的默认值是全局环境(参见 <a href="#pdf-load"><code>load</code></a>)。
    因此，Lua 代码中的自由名称默认指的是<em>全局环境</em>的条目，因此也称为 <em>全局变量</em>。
    此外，所有标准库都是在全局环境中加载的，其中一些函数操作该环境。
    你可以使用 <a href="#pdf-load"><code>load</code></a>(或 <a href="#pdf-loadfile"><code>loadfile</code></a>)以不同的环境加载一个
    chunk。
    (在 C 中，你必须加载 chunk 然后更改它的第一个 upvalue 的值； 参见 lua_setupvalue)

    <h2>2.3 &ndash; <a name="2.3">错误处理</a></h2>

    <p />
    Lua 中的部分操作会 <em>抛出</em> 错误。
    错误会中断程序的正常流程，程序可以通过 <em>捕获</em> 错误继续执行。

    <p />
    Lua 代码可以通过调用 <a href="#pdf-error"><code>error</code></a> 函数来显式抛出错误(这个函数永远不会返回)。

    <p />
    在 Lua 中，你可以使用 <em>保护调用</em>(<a href="#pdf-pcall"><code>pcall</code></a> 或 <a
        href="#pdf-xpcall"><code>xpcall</code></a>) 来捕获错误。
    函数 <a href="#pdf-pcall"><code>pcall</code></a> 以 <em>保护模式</em> 调用给定的函数。
    运行函数时发生的任何错误都会中止函数的执行，并立即返回给 <code>pcall</code> 一个状态码。

    <p />
    因为 Lua 是一种嵌入式扩展语言， Lua 代码通过宿主程序中的一个调用开始运行。(当你使用独立的 Lua 时，<code>lua</code> 应用程序是宿主程序)
    通常，这个调用是受保护的；
    因此，在编译或执行 Lua 程序块时发生的一个原本不受保护的错误，程序会将控制权返还给宿主，
    宿主可以采取适当的措施，例如：打印一个错误消息。

    <p />
    不论什么时候发生错误，Lua 都会返回一个错误对象。
    Lua 本身生成的错误对象是一个字符串，但是程序可以返回任意类型的错误对象。
    错误对象将交由 Lua 程序或宿主程序来处理。
    由于历史原因，错误对象通常被称为 <em>错误消息</em>，即使它不一定是一个字符串。

    <p />
    当您使用 <a href="#pdf-xpcall"><code>xpcall</code></a> (或 C 中的 <a href="#lua_pcall"><code>lua_pcall</code></a>)时，
    您可以提供一个 <em>错误处理函数</em> 来处理错误。
    这个函数将原来的错误对象作为参数，并返回一个新的错误对象。
    这个函数在错误被抛出之前被调用，因此它可以收集更多关于错误的信息，
    例如，它可以检查栈跟踪并创建堆栈跟踪。
    这个错误处理函数调用仍然受保护的，因此，错误处理函数内部的错误将再次调用错误处理函数(递归)。
    如果这个循环持续太长时间，Lua 会中止它并返回一个适当的错误对象。
    错误处理函数仅用于常规运行时错误。它不会用于内存分配错误或在运行清理器或其它消息处理的情况。

    <p />
    Lua 也提供了<em>警告</em> 系统(参见 <a href="#pdf-warn"><code>警告</code></a>)。
    与错误不同，警告不会以任何方式干扰程序运行。
    它们通常只生成消息给用户，这个行为可以在 C 中修改(参见 <a href="#lua_setwarnf"><code>lua_setwarnf</code></a>)。

    <h2>2.4 &ndash; <a name="2.4">元表与元方法</a></h2>

    <p />
    Lua 中的每个值都能有一个 <em>元表(metatable)</em>，这个 <em>元表</em> 是一个普通的 Lua 表，它定义了原始值在某些情况下的行为。
    您可以通过在元表中设置指定的字段以修改值的一些行为。
    例如，当一个非数字值做为加法的操作数时，Lua 会检查元表中的 <code>__add</code> 字段。
    如果找到一个函数，Lua 会调用这个函数来执行加法。

    <p />
    元表中的每个事件的 key 都是一个带有 "__"(双下划线) 前缀的字符串；
    对应额的值称为 <em>元值(metavalue)</em>。
    大多数时间，元值是一个方法，也称为 <em>元方法(metamethod)</em>。
    在前面的示例中，key 是字符串 "<code>__add</code>"，元方法是执行加法操作的函数。
    除非另有说明，否则一个元方法可以是实际中任何可调用值，它们可能是一个方法或者一个有 <code>__call</code> 元方法的表。

    <p />
    你可以使用 <a href="#pdf-getmetatable"><code>getmetatable</code></a> 函数来查询任何值的元表。
    Lua 在元表中查询元方法时使用原始访问 (参见 <a href="#pdf-rawget"><code>rawget</code></a>)。

    <p />
    你可以通过 <a href="#pdf-setmetatable"><code>setmetatable</code></a> 函数来修改表的元方法。
    你不能在 Lua 代码中修改其它类型值的元方法(除非使用调试库(debug library) (参见 <a href="#6.10">&sect;6.10</a>))。

    <p />
    尽管多个表和用户数据可以共享它们的元表，表和完全用户数据也可以有独属于它们自己的元表，
    所有其它类型的值共享一个元表，即所有数字共享一个元表，所有字符串共享一个元表，等等。
    默认情况下，一个值没有元表，但是字符串库会为字符串类型设置一个元表(参见 <a href="#6.4">&sect;6.4</a>)。

    <p />
    元表操作的完整列表如下。
    每个事件由其相应的 key 标识。
    为了方便，使用的元表键的格式是两个下划线加上小写字母。
    例如，<code>__add</code> 是一个元表键，它表示一个元方法，它用于执行加法操作。

    <ul>
        <li><b><code>__add</code>: </b>
            <code>+</code> 操作。
            如果加法中任何操作数不是数字，Lua 将尝试调用一个元方法。
            首先，Lua 会检查第一个操作数(即使它是数字)，如果该操作数没有定义 <code>__add</code> 元方法，
            Lua 将检查第二个操作数，如果 Lua 可以找到一个元方法，它将调用元方法，并将两个操作数作为参数，调用结果就是加法的结果。
            否则，如果没有找到元方法，Lua 会抛出一个错误。
        </li>

        <li><b><code>__sub</code>: </b>
            <code>-</code> 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__mul</code>: </b>
            <code>*</code> 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__div</code>: </b>
            <code>/</code> 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__mod</code>: </b>
            <code>%</code> 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__pow</code>: </b>
            <code>^</code> (次方) 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__unm</code>: </b>
            <code>-</code> (一元取负) 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__idiv</code>: </b>
            <code>//</code>(向下取整除法) 操作。行为和 "add" 操作类似。
        </li>

        <li><b><code>__band</code>: </b>
            <code>&amp;</code> (按位与)操作。行为和 "add" 操作类似，不同的是 Lua 会在任何一个操作数无法转换为整数时(参见 <a
                href="#3.4.3">&sect;3.4.3</a>)尝试元方法。
        </li>

        <li><b><code>__bor</code>: </b>
            <code>|</code> (按位或)操作。行为和 "band" 操作类似。
        </li>

        <li><b><code>__bxor</code>: </b>
            <code>~</code> (按位异或)操作。行为和 "band" 操作类似。
        </li>

        <li><b><code>__bnot</code>: </b>
            <code>~</code> (按位取反)操作。行为和 "band" 操作类似。
        </li>

        <li><b><code>__shl</code>: </b>
            <code>&lt;&lt;</code> (左移)操作。行为和 "band" 操作类似。
        </li>

        <li><b><code>__shr</code>: </b>
            <code>&gt;&gt;</code> (右移)操作。行为和 "band" 操作类似。
        </li>

        <li><b><code>__concat</code>: </b>
            <code>..</code> (连接)操作。行为和 "add" 操作类似，不同的是 Lua 在任何操作数即不是一个字符串也不是数字(数字总能转换为对应的字符串)的情况下尝试元方法。
        </li>

        <li><b><code>__len</code>: </b>
            <code>#</code> (取长度)操作。
            如果对象不是一个字符串，Lua 将尝试它的元方法。
            如果它找到该方法，Lua会将对象作为参数调用它，调用结果(总是调整为1个结果)就是这个操作的结果。
            如果对象是一个表，但是没有元方法，Lua 使用表的取长度操作(参见 <a href="#3.4.7">&sect;3.4.7</a>)。
            否则，Lua 抛出一个错误。
        </li>

        <li><b><code>__eq</code>: </b>
            (<code>==</code>) 操作。行为和 "add" 操作类似，不同的是 Lua 只会在比较的两个对象都是表或完全用户数据并且它们不是同一个对象时才会尝试元方法。
            结果总是被转换成一个 bool。
        </li>

        <li><b><code>__lt</code>: </b>
            (<code>&lt;</code>) operation。行为和 "add" 操作类似，不同的是 Lua 只会在比较的值既不是字符串也不是数字时才会被尝试元方法。
            结果总是被转换成一个 bool。
        </li>

        <li><b><code>__le</code>: </b>
            (<code>&lt;=</code>) 操作。行为和 "lt" 操作类似。
        </li>

        <li><b><code>__index</code>: </b>
            表索引访问操作 <code>table[key]</code>。
            这个事件发生在 <code>table</code> 不是一个表或当 <code>key</code> 不在 <code>table</code> 中时。
            元值是在 <code>table</code> 的元表中查找的。

            <p />
            该事件的元值可以是函数、表或具有 <code>__index</code> 元值的任何值。
            如果它是函数，则使用 <code>table</code> 和 <code>key</code>
            作为参数进行调用，调用的结果(调整为一个值)是运算操作的结果。
            否则，最终结果是对此元值进行索引 <code>key</code> 的结果。
            这是常规索引，不是原始(raw)的，因此可能会触发另一个 <code>__index</code> 元值。
        </li>

        <li><b><code>__newindex</code>: </b>
            <code>table[key] = value</code> 赋值。
            和 index 事件一样，该事件在 <code>table</code> 不是一个表或当 <code>key</code> 不在 <code>table</code> 中时发生。
            元值是在 <code>table</code> 的元表中查找的。
            <p />
            和 __index 一样，该事件的元值可以是函数、表或具有 <code>__newindex</code> 元值的任何值。
            如果它是一个函数，将使用 <code>table</code>, <code>kek</code> 和 <code>value</code> 作为参数调用这个函数，
            否则，Lua 会在该元值上重复对该索引进行赋值。
            这个赋值是常规的，不是原始(raw)的，因此可能会触发另一个 <code>__newindex</code> 元值(递归)。

            <p />
            每当调用 <code>__newindex</code> 元值时，Lua 不会执行原始赋值。
            如果需要，元值本身可以调用 <a href="#pdf-rawset"><code>rawset</code></a> 来执行赋值。
        </li>

        <li><b><code>__call</code>: </b>
            <code>func(args)</code> (调用操作)。
            这个事件在 Lua 尝试调用一个不是函数的值时触发(即 <code>func</code> 不是一个函数)。
            查找 <code>func</code> 的元方法，如果存在，这个元方法将 <code>func</code> 作为它的第一个参数进行调用。
            这个调用的所有结果都将通过这个操作返回。
            这是唯一一个允许返回多个值的元方法。
        </li>
    </ul>

    <p />
    除了前面的列表，解释器也在元表中接收下面的字段：
    <code>__gc</code> (参见 <a href="#2.5.3">&sect;2.5.3</a>),
    <code>__close</code> (参见 <a href="#3.3.8">&sect;3.3.8</a>),
    <code>__mode</code> (参见 <a href="#2.5.4">&sect;2.5.4</a>) 和 <code>__name</code>
    (当 <code>__name</code> 字段为一个字符串时，可能用于 <a href="#pdf-tostring"><code>tostring</code></a> 和错误消息。

    <p />
    对于一元的操作符(一元负(-)，取长度(#)和按位取反(~))，元方法是用一个虚拟的等于第一个参数的第二操作数来调用。
    这个额外的操作数只是为了简化 Lua 的内部实现(通过使这些操作符行为像二元操作)，并且可能在未来版本中移除。
    对于大多数情况，额外的操作数是无关紧要的。

    <p />
    因为元表也是普通的表，它们能包含任意的字段，
    而不仅仅是上面定义的事件名。
    标准库中的一些函数(例如 <a href="#pdf-tostring"><code>tostring</code></a>)
    使用了元表的其它字段来满足它们自己的目的。

    <p />
    在将一个表设置为某个对象的元表前，将所有需要的元方法添加到表是一个良好的习惯。
    特别是，<code>__gc</code> 元方法仅在遵循此顺序的情况下才工作 (参见 <a href="#2.5.3">§2.5.3</a>)。
    在创建对象后立即设置其元表也是一个良好的的习惯。

    <h2>2.5 &ndash; <a name="2.5">垃圾收集(GC)</a></h2>

    <p />
    Lua 执行自动内存管理。
    这意味着你不需要担心新对象的内存分配和对象不再使用时的内存释放。
    Lua 通过运行 <em>垃圾收集器</em> 来收集所有 <em>死</em> 对象来自动管理内存。
    所有 Lua 使用的内存都受到自动管理：
    strings, tables, userdata, functions, threads, internal structures, etc
    (字符串、表、用户数据、函数、现成、内部结构等)。

    <p />
    一个被收集器确定正常程序执行过程中不能再次被访问到的对象被称为 <em>死</em> 对象。
    (这里的"正常执行"排除了终结器，它能使死对象复活(参见 <a href="#2.5.3">&sect;2.5.3</a>),也排除了使用 debug 库的操作)
    请注意，收集器确定一个对象是死对象的时间可能和程序员预期的不一致。
    Lua 唯一保证的是 Lua 一个仍然可以在程序的正常执行中访问到的对象不会被收集，而且它最终会收集从 Lua 中无法访问的对象。
    (这里的从 Lua 中无法访问，意味着 Lua 之外的代码既没有变量也没有其它活对象引用该对象)
    因为 Lua 对 C 代码一无所知，它不会收集通过注册表(参见 <a href="#4.3">&sect;4.3</a>)访问的对象，包括全局环境。

    <p />
    Lua中的垃圾收集有两种模式：增量和分代。

    <p />
    默认的 GC 模式和参数适合大多数用法。
    然而，花费大量时间在分配和释放内存的程序能受益于其它设置。
    注意 GC 行为在不同平台和不同 Lua 版本之间是不可移植的；
    因此，最佳设置也是不可移植的。

    <p />
    你可以通过在 C 中调用 <a href="#lua_gc"><code>lua_gc</code></a> 或在
    Lua 中调用 <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> 来改变gc模式和参数。
    你也可以使用这些方法直接控制收集器(例如，开始和重启收集器)。

    <h3>2.5.1 &ndash; <a name="2.5.1">增量式GC</a></h3>

    <p />
    在增量模式中，
    每次 GC 执行在程序执行过程中以小步执行标记-清除收集。

    在这个模式中，
    收集器使用三个数字来控制垃圾收集周期：
    <em>garbage-collector pause(垃圾收集器间歇率)</em>, <em>garbage-collector step multiplier(垃圾收集器步进倍率)</em> 和 <em>
        garbage-collector step size(垃圾收集器步长)</em>。

    <p />
    <em>garbage-collector pause(垃圾收集器间歇率)</em>控制收集器开启新周期前需要等待多久。
    当内存使用达到上一次收集的 <em>n%</em> 时，收集器将开始一个新的周期。
    更大的值将使收集器更不活跃。当值 &lt;= 100 意味着收集器开启新周期不会进行等待。200表示收集器等待使用的内存达到前一周期的两倍。
    默认值是200；最大值为1000。

    <p />
    <em>garbage-collector step multiplier(垃圾收集器步进倍率)</em>
    控制收集器相对与内存分配的速度，即每千字节分配时，收集器会标记或清除多少个元素。
    大的值使收集器更积极，但也增加了每个增量步骤的大小。
    你不应该使用小于100的值，因为它使收集器太慢，并且可能导致收集器永远无法完成一个周期。
    默认值是100，最大值为1000。

    <p />
    <em>garbage-collector step size(垃圾收集器步长)</em>控制每个增量步骤的步长。

    这个参数是对数：
    值为<em>n</em>意味着解释器将分配<em>2<sup>n</sup></em>字节，并在步骤中执行等效的工作量。
    大的值(例如，60)使收集器成为一个全量式(非增量式)收集器。
    默认值是13，意味着每个增量步骤大约为8&nbsp;Kbytes。

    <h3>2.5.2 &ndash; <a name="2.5.2">分代式GC</a></h3>

    <p />
    在分代模式中，收集器会频繁地进行 <em>minor(次要)</em> 收集，它只遍历最近创建的对象。
    如果 minor 收集后内存使用量仍大于一个限制，收集器会执行停止世界运作(stop-the-world)的 <em>major(主要)</em> 收集，它遍历所有对象。
    分代模式有两个参数: <em>minor multiplier(次要倍率)</em> 和 <em>major multiplier(主要倍率)</em>。

    <p />
    次要倍率控制次要收集的频率。
    对于次要倍率 <em>x</em>，当内存使用量比前一次主要收集后的内存使用量增长 <em>x%</em> 时，将会执行一个新的次要收集。
    例如，对于倍率为 20 的情况下，收集器将在内存使用量比前一次主要收集后的内存使用量增长 20% 时执行次要收集。
    默认值为 20，最大值为 200。

    <p />
    主要倍率控制主要收集的频率。
    对于主要倍率 <em>x</em>，当内存使用量比前一次主要收集后的内存使用量增长 <em>x%</em> 时，将会执行一个新的主要收集。
    例如，对于倍数为 100 的情况下，收集器将在内存使用量超过上次收集后使用量两倍时执行主要收集。
    默认值为 100，最大值为 1000。

    <h3>2.5.3 &ndash; <a name="2.5.3">GC元方法</a></h3>

    <p />
    你可以为表设置 GC 元方法，对于完全用户数据(参见 <a href="#2.4">&sect;2.4</a>)，则需要使用 C API。
    这些元方法，称为终结器，在垃圾收集发现相应的表或用户数据死亡时被调用。
    终结器允许你协调 Lua 的垃圾收集与外部资源管理，例如关闭文件、网络或数据库连接或释放自己的内存。

    <p />
    为了在一个对象(表或完全用户数据)被收集时被终结，你必须为它的终结标记。
    当为它设置一个带有 <code>__gc</code> 的元方法时，你就为它的终结做了标记。
    注意，如果你设置元表时没有 <code>__gc</code> 字段，并且在之后创建了该字段，该对象将不会为终结做标记。

    <p />
    当一个对象死亡时，它不会立即被垃圾收集器收集。
    取而代之的是，Lua 将它放入一个列表。
    收集之后，Lua 遍历这个列表，它检查对象的 <code>__gc</code> 元方法：
    如果它存在，Lua 将把这个对象作为它的唯一参数进行调用。

    <p />
    每个收集周期的末尾，Lua 按照标记的反顺序调用所有在该周期中被收集的对象终结器，
    换句话说，第一个被调用的终结器是最后标记的对象的终结器。
    每个终结器的执行可以在程序的任何地方进行。

    <p />
    由于正在收集的对象仍必须由终结器使用，Lua 必须复活这些对象(和其它只能被终结器访问的对象)。
    通常，这种复活是短暂的，并且对象内存将在下一个GC周期被释放。
    然而，如果终结器在一些全局位置保存了对象(例如，全局变量)，这种复活将是长久的。
    此外，如果终结器又标记了这个对象，那么在下一个这个对象被标记为死亡的周期，这个终结器会被再次调用。
    在任何情况，对象内存只在对象死亡并且没有终结标记的 GC 周期被释放。

    <p />
    当你关闭一个状态机(参见 <a href="#lua_close"><code>lua_close</code></a>)时，
    Lua 调用所有被标记为终结的对象的终结器，按照标记的反顺序进行调用。
    如果终结器在这个阶段标记了对象进行收集，这些标记将没有效果。

    <p />
    终结器不能挂起或运行垃圾收集器。
    由于它们可能在不可预知的时间运行，因此将每个终结器限制为最小的必要操作以正确释放相关资源是良好的习惯。

    <p />
    运行终结器时的错误会生成一个警告；错误不会被传播。

    <h3>2.5.4 &ndash; <a name="2.5.4">弱表</a></h3>

    <p />
    <em>weak table(弱表)</em> 是有 <em>weak references(弱引用)</em> 元素的表。
    弱引用是一种被垃圾收集器忽略的引用，
    换句话说，如果一个对象的所有引用都是弱引用，垃圾收集器将会收集这个对象。

    <p />
    一个弱表可以是弱键，弱值或弱键值。
    一个有弱值的表允许它的值被收集，但是不允许它的键被收集。
    一个弱键值表允许它的键和值都被收集。
    在任何情况下，如果键或值被收集，对应的整个键值对从表中被移除。
    一个表的弱性是通过它的元表的 <code>__mode</code> 字段控制的。
    如果元表中存在 <code>__mode</code> 字段，
    它的值必须是下面的字符串之一：
    "<code>k</code>"，表示表有弱键；
    "<code>v</code>"，表示表有弱值；
    或者 "<code>kv</code>"，表示表有弱键和弱值。

    <p />
    一个有弱键强值的表也被称为一个 <em>蜉蝣表(ephemeron table)</em>，
    在一个蜉蝣表中，值是否可达取决于它的键是否可达。
    特别注意，如果一个键仅仅被它的值所引用，那么这个键值对将被移除。

    <p />
    对表弱属性的所有修改会在下一个收集周期才生效。
    特别注意，如果你将一个表的弱属性改为强。
    Lua 可能仍然会在这个修改生效前收集一些项。

    <p />
    只有有显式构造的对象才会被从弱表中移除。
    值，例如数字和轻量级C函数，不会被垃圾收集器收集，因此不会从弱表中被移除(除非它们的关联值被收集)。
    尽管字符串会被垃圾收集器收集，但它们没有显式构造，并且它们的相等性基于值；
    它们的行为更像值而不是对象。因此，它们不会被从弱表移除。

    <p />
    复活对象(即，正在执行终结器的对象和只能通过正在执行终结器的对象的访问的对象)在弱表中有一个特殊行为。
    在运行其终结器前，它们会从弱值表中移除，但是运行终结器之后，它们会在实际释放对象的下一个周期中从弱键表中移除。
    这种行为允许终结器通过弱表访问与对象关联的属性。

    <p />
    如果一个弱表在收集周期中是被复活对象之一，则在下一个周期之前，它可能无法被正确清除。

    <h2>2.6 &ndash; <a name="2.6">协程(coroutine)</a></h2>

    <p />
    Lua 支持协程，也称 <em>协作式多线程</em>。
    一个协程在 Lua 中表示一个独立的执行线程。
    然而，与多线程系统中的线程不同，一个线程只能通过显式调用一个 yield 函数才能暂停其执行。

    <p />
    你可以通过调用 <a href="#pdf-coroutine.create"><code>coroutine.create</code></a> 来创建一个协程。
    它唯一的参数是一个函数，它是协程的 "main" 函数。
    <code>create</code> 函数值创建一个新协程，并返回一个句柄(一个类型为 <em>线程</em> 的对象)，而不会启动协程。

    <p />
    你可以通过调用 <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 执行一个协程。
    当你第一次调用 <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 时，
    传递的第一个参数应该是一个由 <a href="#pdf-coroutine.create"><code>coroutine.create</code></a> 返回的线程，
    协程会开始执行，并调用其主函数。
    额外的参数将会作为主函数的参数。
    协程开始运行后，它会一直运行直至结束或者 "yield(让出)"。

    <p />
    终止一个协程的运行有两种方式：
    正常情况是主函数运行返回(显示返回或运行完最后一个指令)。
    异常情况是发生未受保护的错误。

    在正常终止情况下，<a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 返回 <b>true</b>，加上所有协程主函数返回的所有值。
    在异常情况下，<a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 返回 <b>false</b>，加上一个错误对象。
    在这种情况下，协程不会撤销其堆栈，因此你可以在错误发生后使用调试 API 进行检查。

    <p />
    协程通过调用 <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a> 来进行让出(yield)操作，
    当协程让出时，相应的 <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 立即返回，
    即使让出操作发生在嵌套函数调用内部(即，不是在主函数中，而是由主函数直接或间接调用中的函数中)。
    在让出时，<a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 也会返回 <b>true</b>，
    加上所有传递给 <a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a>的参数。
    当你再次恢复同一个协程时，它会从让出的位置继续它的执行，<a href="#pdf-coroutine.yield"><code>coroutine.yield</code></a> 调用将返回 <a 
        href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 的所有额外参数。

    <p />
    就像 <a href="#pdf-coroutine.create"><code>coroutine.create</code></a> 一样，
    <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> 函数也创建一个协程，
    但返回的不是一个协程，它返回一个函数，当这个函数被调用时，启动这个协程。
    所有传递给这个函数的参数作为 <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 的额外参数。
    <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> 返回所有
    <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 返回的除第一个(bool 类型错误码)外的值。
    与 <a href="#pdf-coroutine.resume"><code>coroutine.resume</code></a> 不同,
    由 <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> 创建的函数传递所有错误给调用者。
    在这种情况下，函数还会关闭协程(参见 <a href="#pdf-coroutine.close"><code>coroutine.close</code></a>)。

    <p />
    下面的代码是一个协程工作的范例：

    <pre>
     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end

     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)

     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))
</pre>
    <p />
    但你运行这个程序，会产生以下输出：

    <pre>
     co-body 1       10
     foo     2
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine
</pre>

    <p />
    你也可以通过 C API 来创建和操作协程。
    参见函数 <a href="#lua_newthread"><code>lua_newthread</code></a>,
    <a href="#lua_resume"><code>lua_resume</code></a> 和 <a href="#lua_yield"><code>lua_yield</code></a>。

    <h1>3 &ndash; <a name="3">语言定义</a></h1>

    <p />
    本节描述了 Lua 的词法、语法和语义。
    换句话说，本节描述了哪些标记是有效的，它们如何组合，以及它们的组合意义。

    <p />
    语言结构将通过通常的扩展 BNF 符号来描述，
    其中 {<em>a</em>} 表示 0 或多个 <em>a</em>，而 [<em>a</em>] 表示一个可选的 <em>a</em>。
    非终端标识符显示成这样 non-terminal，关键词显示成这样 <b>kword</b> ,其它中断符号显示成这样 &lsquo;<b>=</b>&rsquo;。
    完整语法可以在本手册最后的 <a href="#9">&sect;9</a> 中找到。

    <h2>3.1 &ndash; <a name="3.1">词法约定</a></h2>

    <p />
    Lua 语言的格式自由。它会忽略语法元素(符记)间的空格(包括换行)和注释，仅把它们看作为名字和关键字间的分割符。
    Lua 将标准 ASCII 空白字符(空格、换行、换行、回车、水平制表符和垂直制表符)识别为空格。

    <p />
    <em>名称(Name)</em>(也称为 <em>标识符</em>)在 Lua 中可以是任何由字母、数字和下划线组成的字符串，不能以数字开头且不能是保留字。

    <p />
    下面 <em>关键词</em> 被保留而且不能作为名称：

    <pre>
     and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while
</pre>

    <p />
    Lua 对大小写敏感：
    <code>and</code> 是一个保留字，但是 <code>And</code> 和 <code>AND</code> 是两个不同的有效名称。
    作为约定，程序应该避免创建以下划线开头后面跟随一个或多个大写字母(例如 <a href="#pdf-_VERSION"><code>_VERSION</code></a>)的名字。

    <p />
    下面字符串是另外一些符号标记：

    <pre>
     +     -     *     /     %     ^     #
     &amp;     ~     |     &lt;&lt;    &gt;&gt;    //
     ==    ~=    &lt;=    &gt;=    &lt;     &gt;     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...
</pre>

    <p />
    <em>字符串</em> 可以通过匹配的单引号或双引号来界定，
    并且可以包含 C 风格的转义序：
    '<code>\a</code>' (警报), '<code>\b</code>' (退格),
    '<code>\f</code>' (换页), '<code>\n</code>' (换行), '<code>\r</code>' (回车),
    '<code>\t</code>' (水平制表符), '<code>\v</code>' (垂直制表符), '<code>\\</code>' (反斜杠),
    '<code>\"</code>' (双引号) 和 '<code>\'</code>' (单引号)。

    在一个反斜杠后跟随一个换行等价于在字符串中写一个换行符。
    转义串 '<code>\z</code>' 会忽略其后的一系列空白符，包括换行；他在你需要将长字面值字符串分隔并缩进为多行而不向字符串内容中添加换行符和空格是特别有用的。
    短字面字符串不能包含未转义的换行符或不构成有效的转义序列的转义符。

    <p />
    Lua 中的字符串可以保存任意 8 位值，其中包括用 '<code>\0</code>' 表示的 0。
    一般而言，你可以用字符的数字值来表示这个字符。
    方式是用转义串 <code>\x<em>XX</em></code>，
    此处的 <em>XX</em> 必须是恰好两个字符的 16 进制数。
    或者你也可以使用转义串 <code>\<em>ddd</em></code> ，
    这里的 <em>ddd</em> 是一到三个十进制数字。
    (注意，如果在转义符后接着恰巧是一个数字符号的话，
    你就必须在这个转义形式中写满三个数字。)

    <p />
    UTF-8 编码的 Unicode 字符可以用在通过转义序列 <code>\u{<em>XXX</em>}</code>(必须使用括号包围) 插入的字符串中，
    其中 <em>XXX</em> 是一串 16 进制数字，表示字符的 Unicode 代码点。
    这个代码点可以是小于 <em>2<sup>31</sup></em> 的任何值。
    (Lua 在这里使用了原始 UTF-8 规范，该规范不限制有效的 Unicode 代码点)

    <p />
    字符串也可以通过封闭的 <em>长括号</em> 的长格式来定义。
    我们定义 <em>等级为 <em>n</em> 的开启长括号</em> 为：一个开启方括号，后面跟着 n 个等号，然后再跟一个开启方括号。
    所以，一个等级为 0 的开启长括号写为 <code>[[</code>，等级为1的开启长括号写为 <code>[=[</code>，以此类推。
    <em>关闭长括号</em> 的定义类似;
    例如，等级为 4 的关闭长括号写作 <code>]====]</code>。
    <em>长字符串</em>以任意等级的开启长括号开始，并在第一个相同等级的关闭长括号结束。
    它可以包含除相同等级的关闭括号外的任何文本。
    这种括号形式下的字面量可以跨越多行，不解释任何转义序列，并忽略其它等级的长括号。
    任何类型的行尾序列(回车、换行、回车加换行、或换行加回车)都被转换为简单的换行。
    当开启长括号后立即跟有换行符时，该换行符不包括在字符串中。

    <p />
    作为示例，在一个使用 ASCII 的系统中(其中 <code>a</code> 编码为 97，换行符编码为 10，<code>1</code> 编码为49)，
    下面五个字符串表示的是同一个字符串：

    <pre>
     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]
</pre>

    <p />
    字符串中的任何没有受到前面规则影响的字节都将代表其自身。
    然而，Lua 以文本模式打开文件进行解析，系统文件函数处理某些控制字符可能会遇到问题。
    因此，将二进制数据表示为带有非文本字符显式转义序列的带引号的文字会更安全。

    <p />
    <em>数值常量</em>(或<em>数字</em>)可以写成带有可选的小数部分和可选的十进制指数的形式，指数部分由字母 '<em>e</em>' 或 '<em>E</em>' 标记。
    Lua 也接收十六进制常量，它们以 <code>0x</code> 或 <code>0X</code> 开头。
    十六进制常量也可以接受可选的小数部分和可选的二进制指数，该指数部分由字母 '<code>p</code>' 或 '<code>P</code>' 标记，并用十进制表示。
    (例如，<code>0x1.fp10</code> 表示1984，即 <em>0x1f / 16</em> 乘以 <em>2<sup>10</sup></em>)。

    <p />
    带有小数点或指数的数值常量表示一个浮点数；否则，如果它的值适合整数或者是十六进制常量，它表示一个整数；否则(十进制整数数字溢出时)，它表示一个浮点数。
    既没有小数点也没有指数的十六进制数字总是表示一个整数值；
    如果值溢出了，它会 <em>回绕</em> 以适应一个有效的整数。

    <p />
    有效整数常量示例：

    <pre>
     3   345   0xff   0xBEBADA
</pre>
    <p />
    有效浮点数示例：

    <pre>
     3.0     3.1416     314.16e-2     0.31416E1     34e1
     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1
</pre>

    <p />
    字符串外任何地方，以双横线(<code>--</code>)开头的文本被解释为注释。
    如果紧跟在 <code>--</code> 后的文本不是一个开启长括号，那么这个注释是一个 <em>短注释</em>，它一直持续到行尾。
    否则，它是一个 <em>长注释</em>，它一直持续到相应的关闭长括号。

    <h2>3.2 &ndash; <a name="3.2">变量</a></h2>

    <p />
    变量是存储值的地方。
    在 Lua 中，有三种变量：
    全局变量，局部变量和表的字段。

    <p />
    一个单独的名字可以表示一个全局变量或局部变量(或一个函数的形参，这是一种特殊的局部变量)：

    <pre>
	var ::= Name
</pre>
    <p />
    名字表示标识符(参见 <a href="#3.1">&sect;3.1</a>).

    <p />
    除非显式声明，否则任何的变量名都被当做全局变量。
    局部变量有其 <em>作用范围</em> ：局部变量可以被定义在它作用范围中的函数自由使用(参见 <a href="#3.5">&sect;3.5</a>)。

    <p />
    变量第一次赋值之前，它的值是 <b>nil</b>。

    <p />
    方括号用于索引表。

    <pre>
	var ::= prefixexp &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo;
</pre>
    <p />
    访问表字段的含义可以通过元表来改变(参见 <a href="#2.4">&sect;2.4</a>)改变。

    <p />
    <code>var.Name</code> 只是对应 <code>var["Name"]</code> 的语法糖

    <pre>
	var ::= prefixexp &lsquo;<b>.</b>&rsquo; Name
</pre>

    <p />
    对全局变量 <code>x</code> 的访问等价于 <code>_ENV.x</code>。
    由于编译过程的原因，变量 <code>_ENV</code> 本身永远不会是全局变量(参见 <a href="#2.2">&sect;2.2</a>)。

    <h2>3.3 &ndash; <a name="3.3">语句(stat)</a></h2>

    <p />
    Lua 支持与其它传统语言相似的近乎传统的语句集。该集合包括 块、赋值、控制结构、函数调用和变量声明。

    <h3>3.3.1 &ndash; <a name="3.3.1">语句块(block)</a></h3>

    <p />
    语句块是一系列语句，它们按顺序依次执行：

    <pre>
	block ::= {stat}
</pre>
    <p />
    Lua 支持 <em>空语句</em>，允许你以分号分隔语句，
    通过一个分号开始语句块，或者在序列中连续写两个分号来获得空语句。

    <pre>
	stat ::= &lsquo;<b>;</b>&rsquo;
</pre>

    <p />
    函数调用和赋值都可以以开括号开头。
    这可能性导致 Lua 语法产生歧义。
    考虑以下片段：

    <pre>
     a = b + c
     (print or io.write)('done')
</pre>
    <p />
    语法上可能有两种方式去解释方式：

    <pre>
     a = b + c(print or io.write)('done')

     a = b + c; (print or io.write)('done')
</pre>
    <p />
    当前解释器总是以第一种方式去解释这种结构，
    将开括号作为调用参数的开始，
    为了避免这种歧义，
    总是在以括号开头的语句前加一个分号是良好的习惯。

    <pre>
     ;(print or io.write)('done')
</pre>

    <p />
    一个块可以被明确限定以产生一个语句

    <pre>
	stat ::= <b>do</b> block <b>end</b>
</pre>
    <p />
    明确块在控制变量声明作用于是非常有用，
    明确块也在一些时候用于在另一个块中间添加一个 <b>return</b> 语句
    (参见 <a href="#3.3.4">&sect;3.3.4</a>)。

    <h3>3.3.2 &ndash; <a name="3.3.2">代码块(chunks)</a></h3>

    <p />
    一个完整的 Lua 单元被称为 <em>代码块</em>。
    从语法构成上说，一个代码块就是一个语句块：

    <pre>
	chunk ::= block
</pre>

    <p />
    Lua 将代码块作为一个有可变数量参数的匿名函数的函数体(参见 <a href="#3.4.11">&sect;3.4.11</a>)，
    因此，代码块可以定义局部变量，接收参数，并返回值。
    此外，这个匿名函数在编译时会在一个外部局部变量 <code>_ENV</code> 的作用域下运行(参见 <a href="#2.2">&sect;2.2</a>)。
    由此产生的函数总是将<code> _ENV </code>作为其唯一的外部变量，即使它没有使用这个变量。

    <p />
    一个代码块可以存储在文件中或宿主程序的一个字符串中。
    要执行一个代码块，Lua 首先要 <em>load</em>它，
    编译代码块的代码为虚拟机的指令，然后 Lua 使用虚拟机的解释器执行编译后的代码。

    <p />
    代码块也可以被编译成二进制形式。
    相关信息请参阅 <code> Lua c </code>程序和函数 <code>string.dump</code>。
    源码和编译后的程序是可互相转换的；
    Lua 自动检测文件类型并且执行相应的处理(参见 <a href="#pdf-load"><code>load</code></a>)。

    <h3>3.3.3 &ndash; <a name="3.3.3">赋值</a></h3>

    <p />
    Lua 允许多重赋值。
    因此，赋值的语法定义是等号左边放一个变量列表，而等号右边放一个表达式列表。
    两边的列表中的元素都用逗号间开：

    <pre>
	stat ::= varlist &lsquo;<b>=</b>&rsquo; explist
	varlist ::= var {&lsquo;<b>,</b>&rsquo; var}
	explist ::= exp {&lsquo;<b>,</b>&rsquo; exp}
</pre>
    <p />
    表达式在 <a href="#3.4">&sect;3.4</a> 中进行讨论。

    <p />
    在赋值前，值列表会 <em>调整</em> 到变量列表的长度(参见 <a href="#3.4.12">&sect;3.4.12</a>)。

    <p />
    在一次多重赋值中如果一个变量既被赋值又被访问，Lua 保证所有的值读取在赋值之前，
    因此，下面的代码

    <pre>
     i = 3
     i, a[i] = i+1, 20
</pre>
    <p />
    设置 <code>a[3]</code> 为 20, 而不会影响 <code>a[4]</code>。
    因为 <code>a[i]</code> 中的 <code>i</code> 在被赋值为 4 之前就被计算出来了(当时是 3 )。
    简单说 ，这样一行

    <pre>
     x, y = y, x
</pre>
    <p />
    交换 <code>x</code> 和 <code>y</code>，

    <pre>
     x, y, z = y, z, x
</pre>
    <p />
    会轮换 <code>x</code>，<code>y</code>，<code>z</code> 的值。

    <p />
    请注意，这个保证只涵盖在了赋值语句的内部访问。
    如果赋值过程中一个函数或元方法改变了变量的值，Lua 没有保证这个访问顺序。

    <p />
    对一个全局名称的赋值 <code>x = val</code> 等价于赋值语句 <code>_ENV.x = val</code> (参见 <a href="#2.2">&sect;2.2</a>)。

    <p />
    对表字段和全局变量(实际上也是表字段)的赋值含义可以通过元表改变(参见 <a href="#2.4">&sect;2.4</a>)。

    <h3>3.3.4 &ndash; <a name="3.3.4">控制结构</a></h3>
    <p />
    控制结构 <b>if</b>, <b>while</b> 和 <b>repeat</b> 符合通常的意义，而且也有类似的语法：

    <pre>
	stat ::= <b>while</b> exp <b>do</b> block <b>end</b>
	stat ::= <b>repeat</b> block <b>until</b> exp
	stat ::= <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b>
</pre>
    <p />
    Lua 也有 <b>for</b> 语句，它有两种形式(参见 <a href="#3.3.5">&sect;3.3.5</a>)。

    <p />
    控制结构的表达式可以返回任何值。
    <b>false</b> 和 <b>nil</b> 都被视为假。
    所有其它值都视为真。
    特别注意，0 和空字符串也视为真。

    <p />
    在 <b>repeat</b>&ndash;<b>until</b> 循环中，
    内部语句块的结束点不是在 <b>until</b> 这个关键词，
    它还包括了其后的条件表达式。
    因此，条件表达式中可以使用循环内部语句块中的定义的局部变量。

    <p />
    <b>goto</b> 语句转移程序控制点到一个标签出。
    从语法角度来说，Lua 中的标签也被视为语句：

    <pre>
	stat ::= <b>goto</b> Name
	stat ::= label
	label ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;
</pre>

    <p />
    标签在定义它的整个块中可见，嵌套函数内部除外。
    goto 可以跳转到任何可见标签，只要它没有进入局部变量的作用域。
    一个标签不应该在同名标签可见的地方声明标签，即使该同名标签声明在一个封闭语句块中。

    <p />
    <b>break</b> 语句中断 <b>while</b>, <b>repeat</b>, or <b>for</b> 循环的执行，
    跳转到循环后的下一个语句：

    <pre>
	stat ::= <b>break</b>
</pre>
    <p />
    <b>break</b> 结束最内层的循环。

    <p />
    <b>return</b> 语句用于从一个函数或代码块(作为一个匿名函数处理)中返回值。
    函数可以返回多个返回值，因此 <b>return</b> 语句的语法如下：

    <pre>
	stat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]
</pre>

    <p />
    <b>return</b> 只能被写在语句块的最后一句。
    如果需要在语句块中间进行 <b>返回(return)</b> 你可以显式定义一个内部语句块，写作 <code>do return end</code> ，
    因为这样 <b>return</b> 就是这个(内部)语句块的最后一条语句了。

    <h3>3.3.5 &ndash; <a name="3.3.5">for 语句</a></h3>

    <p />
    <b>for</b> 语句有两种形式: 一种数字形式和一种通用模式。

    <h4>数字形式 <b>for</b> 循环</h4>
    <p />
    数字形式的 <b>for</b> 循环在一个控制变量通过一个数学等差运算重复运行代码块。
    它的语法如下:

    <pre>
	stat ::= <b>for</b> Name &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b>
</pre>
    <p />
    给定的标识符(<em>Name</em>)定义了控制变量，它是循环体(<em>block</em>)中新的局部变量。

    <p />
    循环首先运行三个控制表达式以求值。
    它们的值分别是 <em>初始化值</em>, <em>限制值</em> 和 <em>步长</em>。
    如果步长省略，它默认是 1。

    <p />
    如果初始化变量和步长都是整数，则通过整数进行循环。
    注意限制值可能不是一个整数。
    除此之外，三个值都被转换为浮点数并且通过浮点数进行循环。
    在这种情况下，要注意浮点数精度。

    <p />
    初始化之后，循环体重复执行，控制变量从初始值开始，进行公差为步长的等差运算。
    如果步长为负数会生成一个递减序列；步长为零会抛出一个错误。
    循环在值小于等于(步长为负数时，大于等于)限制值时继续运行。
    如果初始化值已经大于(步长为负数时，小于)限制值，循环体不会执行，循环结束。

    <p />
    对于整数循环，控制变量不会发生回绕，而是在溢出时终止循环。

    <p />
    你不应该在循环过程中修改控制变量。
    如果需要在循环之后访问它的值，请在循环结束前将它的值赋给另一个变量。

    <h4>通用形式 <b>for</b> 循环</h4>

    <p />
    通用形式 <b>for</b> 语句通过一个叫 <em>迭代器</em> 的函数工作。
    每一次迭代，迭代器函数将被调用，产生一个新的值，当这个值为 <b>nil</b> 时，循环终止。
    通用形式 <b>for</b> 循环语法如下:

    <pre>
	stat ::= <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b>
	namelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}
</pre>
    <p />
    这种 <b>for</b> 语句

    <pre>
     for <em>var_1</em>, &middot;&middot;&middot;, <em>var_n</em> in <em>explist</em> do <em>body</em> end
</pre>
    <p />
    将按以下方式工作：

    <p />
    名称 <em>var_i</em> 声明了循环体内的循环变量。
    第一个参数就是 <em>控制变量</em>。

    <p />
    循环首先运行 <em>explist</em> 来产生四个值：
    <em>一个迭代器函数</em>，<em>一个状态</em>，一个控制变量的初始值和 <em>一个闭合值</em>。

    <p />
    然后，每次迭代，
    Lua 调用迭代器函数，并传入两个参数：
    <em>状态</em> 和 <em>控制变量</em>。
    这个调用的结果被赋给循环变量，这个赋值操作遵循多重赋值的规则(参见 <a href="#3.3.3">&sect;3.3.3</a>)。
    如果控制变量为 <b>nil</b>，循环终止。
    否则，执行循环体，然后循环继续下一次迭代。

    <p />
    闭合值行为与 to-be-closed(待关闭)(参见 <a href="#3.3.8">&sect;3.3.8</a>) 变量类似，
    它能用于在循环结束时释放资源，它不会干扰循环。

    <p />
    你不应该在循环过程中修改控制变量的值。

    <h3>3.3.6 &ndash; <a name="3.3.6">函数调用语句</a></h3>
    <p />
    为了允许使用函数的副作用，函数调用可以作为一个语句执行：

    <pre>
	stat ::= functioncall
</pre>
    <p />
    这种情况下，所有的返回值都被抛弃。
    函数调用在 <a href="#3.4.10">&sect;3.4.10</a> 中进行解释。

    <h3>3.3.7 &ndash; <a name="3.3.7">局部声明</a></h3>
    <p />
    局部变量可以在语句块中的任意地方声明。
    声明包含一个初始化赋值操作：

    <pre>
	stat ::= <b>local</b> attnamelist [&lsquo;<b>=</b>&rsquo; explist]
	attnamelist ::=  Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}
</pre>
    <p />
    如果有初始化值，一个初始化值操作和多重赋值操作(参见 <a href="#3.3.3">&sect;3.3.3</a>)的语义相同。
    否则，所有变量被初始化为 <b>nil</b>。

    <p />
    每个名称都可以用属性作为后缀
    (在尖括号中间的名称)

    <pre>
	attrib ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]
</pre>
    <p />
    有两种可用的属性：
    <code>const</code>, 声明一个常量，初始化之后不能再次赋值的变量;
    <code>close</code>, 声明一个待关闭变量 (参见 <a href="#3.3.8">&sect;3.3.8</a>)。
    <error>一个变量列表中最多包含一个待关闭变量。</error>

    <p />
    一个代码块也是语句块 (参见 <a href="#3.3.2">&sect;3.3.2</a>),
    因此可以在任何显式语句块外部的代码块中声明局部变量。

    <p />
    局部变量作用域在 <a href="#3.5">&sect;3.5</a> 进行解释。

    <h3>3.3.8 &ndash; <a name="3.3.8">To-be-closed(待关闭) 变量</a></h3>

    <p />
    一个待关闭变量的行为和局部常量类似，不同的是，当变量离开作用域，包括正常的语句块终止，通过 <b>break</b>/<b>goto</b>/<b>return</b> 退出语句块，或错误退出，这个变量将被 <em>closed(关闭)</em>。

    <p />
    这里 <em>close</em> 一个变量意味着调用它的 <code>__close</code> 元方法的表。
    调用这个元方法时，变量本身作为该方法的第一个参数，如果存在错误将把错误对象作为第二个参数；
    如果没有错误，第二个参数是nil。

    <p />
    赋值给待关闭变量的值必须有一个 <code>__close</code> 元方法或者是一个 <code>假值(false 或 nil)</code>。

    <p />
    如果多个待关闭变量在同一事件中离开作用域，按照它们声明顺序的逆序进行关闭。

    <p />
    如果在运行一个关闭方法时发生错误，这个错误将作为变量定义时的常规错误进行处理。
    之后，其它待处理的关闭方法仍然会被调用。

    <p />
    如果一个协程被让出，并且没有再次启动过，
    一些变量可能永远都不会离开其作用域，因此它们将永远不会被关闭。
    (这些变量在协程中创建，并且它们的作用域一直在协程让出的位置上)。
    同样的，如果协程产生了一个错误而导致协程退出，它不会将栈展开，因此不会关闭所有变量。
    这两种情况下，你可以使用终结器或者调用 <a href="#pdf-coroutine.close"><code>coroutine.close</code></a> 以关闭变量。
    然而，如果协程通过 <a href="#pdf-coroutine.wrap"><code>coroutine.wrap</code></a> 来创建，当错误发生时，对应的函数将关闭协程。

    <h2>3.4 &ndash; <a name="3.4">表达式(exp)</a></h2>

    <p />
    Lua 中的基础表达式有如下：

    <pre>
	exp ::= prefixexp
	exp ::= <b>nil</b> | <b>false</b> | <b>true</b>
	exp ::= Numeral
	exp ::= LiteralString
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::= &lsquo;<b>...</b>&rsquo;
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;
</pre>

    <p />
    数字 和 字符串 在 <a href="#3.1">&sect;3.1</a> 中解释;
    变量(variables) 在 <a href="#3.2">&sect;3.2</a> 中解释;
    函数定义在 <a href="#3.4.11">&sect;3.4.11</a> 中解释;
    函数调用在 <a href="#3.4.10">&sect;3.4.10</a> 中解释;
    表构造器在 <a href="#3.4.9">&sect;3.4.9</a> 中解释。
    可变参数('<code>...</code>'), 只能在有可变参数函数中直接使用; 它们在 <a href="#3.4.11">&sect;3.4.11</a> 解释。

    <p />

    二元运算符包括算数运算符 (参见 <a href="#3.4.1">&sect;3.4.1</a>),
    位运算符 (参见 <a href="#3.4.2">&sect;3.4.2</a>),
    比较运算符 (参见 <a href="#3.4.4">&sect;3.4.4</a>), 逻辑运算符 (参见 <a href="#3.4.5">&sect;3.4.5</a>),
    和字符串连接符 (参见 <a href="#3.4.6">&sect;3.4.6</a>).
    一元运算符包括一元负号 (参见 <a href="#3.4.1">&sect;3.4.1</a>),
    按位取反 (参见 <a href="#3.4.2">&sect;3.4.2</a>),
    逻辑非 (参见 <a href="#3.4.5">&sect;3.4.5</a>) 和 <em>取长度运算符</em> (参见 <a href="#3.4.7">&sect;3.4.7</a>)。

    <h3>3.4.1 &ndash; <a name="3.4.1">数学运算符</a></h3>
    <p />
    Lua 支持下面算数运算符:

    <ul>
        <li><b><code>+</code>: </b>加法</li>
        <li><b><code>-</code>: </b>减法</li>
        <li><b><code>*</code>: </b>乘法</li>
        <li><b><code>/</code>: </b>浮点除法</li>
        <li><b><code>//</code>: </b>向下取整除法</li>
        <li><b><code>%</code>: </b>取模</li>
        <li><b><code>^</code>: </b>乘方</li>
        <li><b><code>-</code>: </b>一元负号</li>
    </ul>

    <p />
    除了乘方和浮点除法，其它算数运算符都遵循以下规则：
    如果两个操作数都是整数，
    则操作是对整数进行的，结果是一个整数。
    否则，如果两个操作数都是数字，则它们被转换为浮点数，
    然后按照机器的规则进行浮点算术运算(通常是 IEEE 754 标准),并且结果是一个浮点数。
    (字符串库中在数学运算时将字符串强制转换为数字 参见 <a href="#3.4.3">&sect;3.4.3</a> 了解更多)

    <p />
    乘方和浮点除法(<code>/</code>)总是将它们的操作数转换为浮点数并且结果总是浮点数。
    乘方使用 ISO&nbsp;C 函数 <code>pow</code> ,因此它也对适用于非整数指数。

    <p />
    向下取整除法 (<code>//</code>) 是一种将商向负无穷大舍入从而得到其操作数的除法，结果是两个操作数浮点除法的向下取整值。

    <p />
    取模定义为除法的余数，其商向负无穷大舍入(向下取整除法)。

    <p />
    当整数运算溢出时，所有操作符进行 <em>回绕</em>。

    <h3>3.4.2 &ndash; <a name="3.4.2">位运算符</a></h3>
    <p />
    Lua 支持以下位运算符:

    <ul>
        <li><b><code>&amp;</code>: </b>按位且</li>
        <li><b><code>&#124;</code>: </b>按位或</li>
        <li><b><code>~</code>: </b>按位异或</li>
        <li><b><code>&gt;&gt;</code>: </b>按位右移</li>
        <li><b><code>&lt;&lt;</code>: </b>按位左移</li>
        <li><b><code>~</code>: </b>一元按位取反</li>
    </ul>

    <p />
    所有的位运算符都将它们的操作数转换为整数 (参见 <a href="#3.4.3">&sect;3.4.3</a>)，操作这些整数的所有位, 并且结果是整数。

    <p />
    左移和右移都会用 0 来填补空缺位。
    负数将向相反反向移动位；绝对值大于等于整数中位数的位移结果是 0 (所有位都被移出去了)。

    <h3>3.4.3 &ndash; <a name="3.4.3">强制转换</a></h3>
    <p />
    Lua 在运行时为一些类型和值提供自动转换。
    位运算符总是将浮点数操作数转换成整数。
    乘方和浮点除法总是将整数转换成浮点数。
    所有应用于混合数字(整数和浮点数)的其它数学运算将整数转换成浮点数。
    C API 也会在根据需要将整数和浮点数进行转换。此外，字符串连接符除了接受字符串外，也接受数字作为参数。

    <p />
    将整数转换成浮点数时，如果整数值有确切的浮点数表示，结果就是这个值。
    否则，转换会取最接近的较大或较小值来表示这个值。这种转换不会失败。

    <p />
    将浮点数转换为整数时，Lua 会检查浮点数是否可以被表示为整数。
    (也就是说，浮点数有一个整数值，并且它在整数表示的范围内)
    如果可以，结果就是这个整数值。
    否则，转换失败。

    <p />
    Lua 在几个有必要的地方将字符串强制转换成数字。
    特别地，字符串库设置了一些元方法，这些元方法试图在所有算术运算中强制转换字符串为数字。
    如果转换失败，库会调用另一个操作数的元方法(如果存在的话)，或者会抛出一个错误。
    注意，位运算符不会执行这种强制转换。

    <p />
    不依赖字符串到数字的隐式转换是一个好的习惯，因为这种转换不总是有效；
    特别地 <code>"1" == 1</code> 的结果是 false， <code>"1" &lt; 1</code> 会抛出一个错误(参见 <a href="#3.4.4">&sect;3.4.4</a>)。
    这种强制转换的存在主要是为了兼容，而且可能会在之后的版本中删除。

    <p />
    字符串根据其语法和 Lua 词法分析器的规则转换为整数或浮点数。
    字符串可能还有前导和尾随空格以及符号。
    所有从字符串到数字的转换都接受点和当前区域标记作为基数字符。
    (然而，Lua 词法分析器只接受一个点)如果字符串不是有效的数字，则转换失败。
    如有必要，第一步的结果将按照之前的浮点数和整数之间的转换规则转换为特定的数字子类型。

    <p />
    数字到字符串的转换使用一种未指定的人类可读格式。
    可使用 <a href="#pdf-string.format"><code>string.format</code></a> 将数字转换成指定格式。

    <h3>3.4.4 &ndash; <a name="3.4.4">比较运算符</a></h3>
    <p />
    Lua 支持以下比较运算符:

    <ul>
        <li><b><code>==</code>: </b>等于</li>
        <li><b><code>~=</code>: </b>不等于</li>
        <li><b><code>&lt;</code>: </b>小于</li>
        <li><b><code>&gt;</code>: </b>大于</li>
        <li><b><code>&lt;=</code>: </b>小于等于</li>
        <li><b><code>&gt;=</code>: </b>大于等于</li>
    </ul>
    <p />
    这些运算符的结果总是 <b>false</b> 或 <b>true</b>。

    <p />
    等于操作符 (<code>==</code>) 首先比较操作数的类型。
    如果它们的类型不同，直接返回 <b>false</b>。
    否则，比较操作数的值。
    如果操作数都是字符串，则它们的字节内容必须相等。
    如果操作数都是数字，则它们的算数值必须相等。

    <p />
    表，用户数据和线程的比较是通过引用进行的。
    两个对象相等的条件是它们是同一个对象。
    每次创建新对象时(表，用户数据或线程)，这个新对象与之前的任何对象都不同。
    函数总是等于它自己。
    有任何可检测到的差异(行为，定义)的函数总是不同。

    <p />
    你可以通过表和用户数据的 <code>__eq</code> 元方法来改变 Lua 比较表和用户数据的方式。(参见 <a href="#2.4">&sect;2.4</a>)。

    <p />
    相等性判断不会将字符串转换成数字，反之亦然。
    因此，<code>"0" == 0</code> 返回 <b>false</b>，<code>t[0]</code> 和 <code>t["0"]</code> 都指向不同的表项。

    <p />
    <code>~=</code> 操作符完全等价于 (<code>==</code>) 操作的反值。

    <p />
    大小操作符以以下方式进行。
    如果参数都是数字，根据它们的算数值进行比较，与它们的子类型无关。
    否则，如果参数都是字符串，根据当前区域设置进行比较。
    再则，Lua 尝试调用 <code>__lt</code> 或 <code>__le</code> 元方法(参见 <a href="#2.4">&sect;2.4</a>)。
    <code>a &gt; b</code> 的比较被转译成 <code>b &lt; a</code>， <code>a &gt;= b</code> 被转译成 <code>b &lt;= a</code>。

    <p />
    根据 IEEE 754 标准，特殊值 NaN 不小于、不等于、也不大于任何值，包括它自己。

    <h3>3.4.5 &ndash; <a name="3.4.5">逻辑运算符</a></h3>
    <p />
    Lua 中的逻辑运算符有 <b>and</b>, <b>or</b> 和 <b>not</b>。
    和控制结构(参见 <a href="#3.3.4">&sect;3.3.4</a>)一样。
    所有的逻辑运算符将 <b>false</b> 和 <b>nil</b> 视为 false，其它任何值视为 true。

    <p />
    <b>not</b> 运算符总是返回 <b>false</b> 或 <b>true</b>。
    如果第一个参数的值是<b>false</b> 或 <b>nil</b>， <b>and</b> 运算符返回它的第一个参数；
    否则，<b>and</b> 返回它的第二个参数。
    如果第一个参数不是 <b>false</b> 或 <b>nil</b>， <b>or</b> 操作符返回第一个参数；
    否则 <b>or</b> 返回第二个参数。
    <b>and</b> 和 <b>or</b> 使用遵循短路规则；
    也就是说，第二个操作数只在需要时执行。
    下面是一些实例：

    <pre>
     10 or 20            --&gt; 10
     10 or error()       --&gt; 10
     nil or "a"          --&gt; "a"
     nil and 10          --&gt; nil
     false and error()   --&gt; false
     false and nil       --&gt; false
     false or nil        --&gt; nil
     10 and 20           --&gt; 20
</pre>

    <h3>3.4.6 &ndash; <a name="3.4.6">字符串连接</a></h3>
    <p />
    Lua 中的字符串连接符写作两个点('<code>..</code>')。
    如果两个操作数都是字符串或数字，数字将通过(参见 <a href="#3.4.3">&sect;3.4.3</a>)的规则被转换成字符串。
    否则 <code>__concat</code> 元方法(参见 <a href="#2.4">&sect;2.4</a>)被调用。

    <h3>3.4.7 &ndash; <a name="3.4.7">取长度操作符</a></h3>

    <p />
    取长度操作符写作一元前置符 <code>#</code>。

    <p />
    字符串的长度是其字节数。
    (就是以一个字符一个字节计算的字符串长度)

    <p />
    取长度操作符应用于一个表时返回表的边界。
    一个表 <code>t</code> 的 <em>边界</em> 是满足以下条件的非负整数：

    <pre>
     (border == 0 or t[border] ~= nil) and
     (t[border + 1] == nil or border == math.maxinteger)
</pre>
    <p />
    边界是表中存在的任何正整数索引，后跟一个缺省索引，加上两种极限情况：当1是缺省时的0和索引值存在整数的最大值。
    注意，非正整数的键不会干扰到这个边界。

    <p />
    只有一个边界的表称为 <em>序列(sequence)</em>。
    例如，表 <code>{10, 20, 30, 40, 50}</code> 是序列，因为它只有一个边界 (5)。
    表 <code>{10, 20, 30, nil, 50}</code> 有两个边界 (3 和 5)，所以它不是序列。
    (索引 4 是一个 <em>洞(hole)</em>)。
    表 <code>{nil, 20, 30, nil, nil, 60, nil}</code>
    有三个边界 (0, 3, 和 6)，所以它不是序列。
    表 <code>{}</code> 有一个边界 0，所以它是序列。

    <p />
    当 <code>t</code> 是一个序列时，
    <code>#t</code> 返回它的唯一边界，对应于序列的长度。
    当 <code>t</code> 不是一个序列时，
    <code>#t</code> 返回它的任何一个边界。(确切的返回值取决于表内部表示的细节，而这又取决于表的填充方式和其非数字键的内存地址)

    <p />
    表长度的计算保证最坏时间复杂度为 <em>O(log n)</em>, <em>n</em> 是表的最大键值。

    <p />
    程序可以通过 <code>__len</code>(参见 <a href="#2.4">&sect;2.4</a>) 元方法修改所有非字符串的取长度操作符行为。

    <h3>3.4.8 &ndash; <a name="3.4.8">优先级</a></h3>
    <p />
    Lua 中的操作符优先级如下表所示，从低到高：

    <pre>
     or
     and
     &lt;     &gt;     &lt;=    &gt;=    ~=    ==
     |
     ~
     &amp;
     &lt;&lt;    &gt;&gt;
     ..
     +     -
     *     /     //    %
     unary operators (not   #     -     ~)
     ^
</pre>
    <p />
    通常，你可以使用圆括号来改一个表达式的优先级。
    连接符('<code>..</code>') 和指数运算符('<code>^</code>')是右结合的。
    其它所有的二元操作符都是左结合的。

    <h3>3.4.9 &ndash; <a name="3.4.9">表构造器</a></h3>
    <p />
    表构造器是构造表的表达式。
    每次构造器被调用，都将创建一个新的表。
    构造器可以用于创建空表或创建一个表并且初始化一些字段。
    构造器的一般语法如下：

    <pre>
	tableconstructor ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp
	fieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;
</pre>

    <p />
    每个形如 <code>[exp1] = exp2</code> 的 <em>field</em> 都为新表添加一个键为 <code>exp1</code> 且值为 <code>exp2</code> 的项。
    一个形如 <code>name = exp</code> 的 <em>field</em> 等价于 <code>["name"] = exp</code>。
    形如 <code>exp</code> 的 <em>field</em> 等价于 <code>[i] = exp</code>，其中 <code>i</code> 是一个从 1 开始不断增长的整数。
    其它格式的项不会影响到这个计数。
    例如：

    <pre>
     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
</pre>
    <p />
    等价于

    <pre>
     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end
</pre>

    <p />
    构造器中的赋值顺序是未定义的。
    (这个顺序只在有重复键时才有影响)

    <p />
    如果列表中最后一个字段是 <code>exp</code> 形式，并且这个表达式是一个多返回值表达式，
    那么这个表达式的所有返回值将连续地进入列表。
    (参见 <a href="#3.4.12">&sect;3.4.12</a>).

    <p />
    字段列表有一个可选的尾部分隔符，方便机器生成代码。

    <h3>3.4.10 &ndash; <a name="3.4.10">函数调用</a></h3>
    <p />
    Lua 中的函数调用语法如下：

    <pre>
	functioncall ::= prefixexp args
</pre>
    <p />
    函数调用时，首先对 prefixexp 和 args 进行求值。
    如果 prefixexp 的值是一个 <em>函数</em>，通过给定的参数调用这个函数。
    否则，如果 prefixexp 存在 <code>__call</code> 元方法，那么这个元方法将被调用，
    它的第一个参数是 prefixexp 的值，后面跟着原始调用的参数。(参见 <a href="#2.4">&sect;2.4</a>)

    <p />
    这种格式

    <pre>
	functioncall ::= prefixexp &lsquo;<b>:</b>&rsquo; Name args
</pre>
    <p />
    可以用来调用函数。
    <code>v:name(<em>args</em>)</code> 是 <code>v.name(v,<em>args</em>)</code> 的语法糖，这里的 <code>v</code> 只会被求值一次。

    <p />
    参数(args)语法如下:

    <pre>
	args ::= &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo;
	args ::= tableconstructor
	args ::= LiteralString
</pre>
    <p />
    所有的参数表达式都会在函数调用前计算值。
    <code>f{<em>fields</em>}</code> 格式的调用是等价于 <code>f({<em>fields</em>})</code> 的语法糖，即参数列表是一个单独的新表。
    <code>f'<em>string</em>'</code> 格式的调用是等价于 <code>f('<em>string</em>')</code> 语法糖，即参数是一个单独的字符串。

    <p />
    不在待关闭变量作用域中的 <code>return <em>functioncall</em></code> 格式的调用被称为一个 <em>尾调用</em>。
    Lua 实现了 <em>适当的尾调用</em>(或 <em>适当的尾递归</em>)：在一个尾调用中，被调用的函数将重用调用函数的堆栈。
    因此，程序对执行的嵌套尾调用的数量没有限制。但是，尾调用会擦除调用函数的调试信息。
    注意，只有特定语法才会产生尾调用，其中 <b>return</b> 语句有一个单独的函数调用作为参数，并且它不在任何待关闭变量的作用域中。
    尾调用需要函数完全返回被调用函数的返回值。所以，以下例子都不是尾调用：

    <pre>
     return (f(x))        -- 返回值调整为1个
     return 2 * f(x)      -- 返回值乘以2
     return x, f(x)       -- 额外返回值
     f(x); return         -- 返回值舍弃
     return x or f(x)     -- 返回值调整为1个
</pre>

    <h3>3.4.11 &ndash; <a name="3.4.11">函数定义</a></h3>

    <p />
    函数定义语法如下：

    <pre>
	functiondef ::= <b>function</b> funcbody
	funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>
</pre>

    <p />
    下列语法糖简化了函数定义：

    <pre>
	stat ::= <b>function</b> funcname funcbody
	stat ::= <b>local</b> <b>function</b> Name funcbody
	funcname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]
</pre>
    <p />
    语句

    <pre>
     function f () <em>body</em> end
</pre>
    <p />
    转译成

    <pre>
     f = function () <em>body</em> end
</pre>
    <p />
    语句

    <pre>
     function t.a.b.c.f () <em>body</em> end
</pre>
    <p />
    转译成

    <pre>
     t.a.b.c.f = function () <em>body</em> end
</pre>
    <p />
    语句

    <pre>
     local function f () <em>body</em> end
</pre>
    <p />
    转译成

    <pre>
     local f; f = function () <em>body</em> end
</pre>
    <p />
    而不是

    <pre>
     local f = function () <em>body</em> end
</pre>
    <p />
    (只会在函数体内包含 <code>f</code> 的引用时有区别)

    <p />
    函数定义是一个可执行的表达式，执行结果是一个类型为 <em>function</em> 的值。
    当 Lua 预编译一个代码块时，它的所有函数体都会被预编译，但它们还没有创建。
    然后，当 Lua 执行函数定义时，函数会被 <em>实例化</em> (或 <em>关闭</em>)。
    这个函数实例，或 <em>闭包</em>，是表达式的最终值。

    <p />
    形参被看做局部变量，初始化为调用函数的参数值:

    <pre>
	parlist ::= namelist [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;
</pre>
    <p />
    当一个 Lua 函数被调用时，会调整参数列表到形参列表的长度 (参见 <a href="#3.4.12">&sect;3.4.12</a>)，
    除非函数是可变参数函数(在参数列表的最后使用了 <code>...</code>)，
    在这种情况下，不会调整参数列表；取而代之的是，它会收集所有的额外参数，并将它们提供给 <em>可变参数表达式(写作<code>...</code>)</em>，
    可变参数表达式的值是一个包含所有实际额外参数的列表，类似于函数返回多个值的情况。(参见 <a href="#3.4.12">&sect;3.4.12</a>).

    <p />
    作为示例，考虑以下定义:

    <pre>
     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end
</pre>
    <p />
    下面看看实参到形参数以及可变长参数的映射关系：

    <pre>
     CALL             PARAMETERS

     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2

     g(3)             a=3, b=nil, ... --&gt;  (nothing)
     g(3, 4)          a=3, b=4,   ... --&gt;  (nothing)
     g(3, 4, 5, 8)    a=3, b=4,   ... --&gt;  5  8
     g(5, r())        a=5, b=1,   ... --&gt;  2  3
</pre>

    <p />
    结果返回使用 <b>return</b> 语句 (参见 <a href="#3.3.4">&sect;3.3.4</a>)。
    如果函数结束时没有遇到 <b>return</b> 语句，
    那么函数不返回结果。

    <p />
    一个函数的返回值个数受系统限制。
    这个限制一定大于1000。

    <p />
    <em>冒号</em> 语法可以用来定义 <em>方法</em>，以添加一个隐式形参 <code>self</code> 到方法中。
    因此，语句

    <pre>
     function t.a.b.c:f (<em>params</em>) <em>body</em> end
</pre>
    <p />
    是下面这条语句的语法糖

    <pre>
     t.a.b.c.f = function (self, <em>params</em>) <em>body</em> end
</pre>

    <h3>3.4.12 &ndash; <a name="3.4.12">表达式列表，多结果及调整</a></h3>

    <p />
    函数调用和可变参数表达式可以返回多个值。
    这种表达式称为 <em>多值表达式</em>。

    <p />
    当多值表达式被用作表达式列表的最后一个元素时，该表达式产生的所有结果都将被添加到由这个表达式列表所产生的值的列表中。
    需要注意的是，在期望得到一个表达式列表的地方，如果只有一个单独的表达式，那么这个表达式就被视为这个(单例)列表的最后一个表达式。

    <p />
    下面是 Lua 期望一个表达式列表的地方：

    <ul>
        <li><b>return</b> 语句,
            例如 <code>return e1, e2, e3</code> (参见 <a href="#3.3.4">&sect;3.3.4</a>).
        </li>

        <li>表构造器,
            例如 <code>{e1, e2, e3}</code> (参见 <a href="#3.4.9">&sect;3.4.9</a>).
        </li>

        <li>函数调用的参数，
            例如 <code>foo(e1, e2, e3)</code> (参见 <a href="#3.4.10">&sect;3.4.10</a>).
        </li>

        <li>多重赋值,
            例如 <code>a , b, c = e1, e2, e3</code> (参见 <a href="#3.3.3">&sect;3.3.3</a>).
        </li>

        <li>局部声明,
            例如 <code>local a , b, c = e1, e2, e3</code> (参见 <a href="#3.3.7">&sect;3.3.7</a>).
        </li>

        <li>通用 <b>for</b> 循环的值初始化,
            例如 <code>for k in e1, e2, e3 do ... end</code> (参见 <a href="#3.3.5">&sect;3.3.5</a>).
        </li>
    </ul>
    <p />
    在最后四种情况中，
    列表表达式的值列表必须被 <em>调整</em> 到特定长度：
    调用非可变参数函数时调整为参数个数 (参见 <a href="#3.4.11">&sect;3.4.11</a>),
    多重赋值或局部声明是调整为变量个数，通用 <b>for</b> 循环时调整为4个值。
    这种 <em>调整</em> 根据以下规则进行：
    如果超过需要的值，额外的值将被丢弃；
    如果少于需要的值，将用 <b>nil</b> 填充。
    当列表表达式以多值表达式结束时，多值表达式的所有结果将在调整前进入列表值。

    <p />
    当多值表达式在表达式列表中使用且不是最后一个元素，
    或者在语法期望单个表达式的地方使用时，
    Lua 会将该表达式的结果列表调整为一个元素。
    特别地，语法期望在括号表达式内只有一个表达式；
    因此，在多值表达式周围添加括号会强制它只产生一个结果。

    <p />
    在语法期望单个表达式的地方，我们很少需要使用可变参数表达式。
    (通常，在可变参数部分之前添加一个常规参数并使用该参数会更简单)
    当有这种需要时，我们建议将可变参数表达式分配给一个单独的变量并使用该变量。

    <p />
    下面是一些多值表达式的使用示例。
    在所有情况下，当构造器需要 "第n个" 结果但是没有 "第n个" 结果时，它使用 <b>nil</b>。

    <pre>
     print(x, f())      -- 打印 x 和 f() 的所有结果。
     print(x, (f()))    -- 打印 x 和 f() 的第一个结果。
     print(f(), x)      -- 打印 f() 的第一个结果 和 x。
     print(1 + f())     -- 打印 1 + f() 的第一个结果。
     local x = ...      -- x 赋值为 可变参数的第一个值。
     x,y = ...          -- x 赋值为 可变参数的第一个值。
                        -- y 赋值为 可变参数的第二个值。
     x,y,z = w, f()     -- x 赋值为 w, y 赋值为 f()的第一个结果。
                        -- z 赋值为 f()的第二个结果。
     x,y,z = f()        -- x 赋值为 f()的第一个结果。
                        -- y 赋值为 f()的第二个结果。
                        -- z 赋值为 f()的第三个结果。
     x,y,z = f(), g()   -- x 赋值为 f()的第一个结果。
                        -- y 赋值为 g()的第一个结果。
                        -- z 赋值为 g()的第二个结果。
     x,y,z = (f())      -- x 赋值为 f()的第一个结果, y 和 z 赋值为 nil。
     return f()         -- 返回 f()的所有结果。
     return x, ...      -- 返回 x 和 所有接收的可变参数。
     return x,y,f()     -- 返回 x, y, 和 f()的所有结果。
     {f()}              -- 使用f()的所有结果创建一个列表。
     {...}              -- 使用所有可变参数创建一个列表。
     {f(), 5}           -- 使用f()的第一个结果和5创建一个列表。
</pre>

    <h2>3.5 &ndash; <a name="3.5">可见性规则</a></h2>

    <p />
    Lua 语言有词法作用域。
    局部变量的作用域从声明语句开始，直到包含它的块的最后一个非空语句。
    (<em>空语句</em> 指标签(label)和空语句(;;))
    考虑下面的例子：

    <pre>
     x = 10                -- global variable
     do                    -- new block
       local x = x         -- new 'x', with value 10
       print(x)            --&gt; 10
       x = x+1
       do                  -- another block
         local x = x+1     -- another 'x'
         print(x)          --&gt; 12
       end
       print(x)            --&gt; 11
     end
     print(x)              --&gt; 10  (the global one)
</pre>

    <p />
    注意这里，像 <code>local x = x</code> 这种声明，
    新的 <code>x</code> 正在被声明，
    所以第二个 <code>x</code> 引用的是外层的 <code>x</code>。

    <p />
    因为有这样一个词法作用域的规则，
    局部变量可以被在它的作用范围内定义的函数自由使用。
    当一个局部变量被内层的函数中使用的时候，
    它被内层函数称作 <em>上值</em>，或是 <em>外部局部变量</em>。

    <p />
    注意每次执行一个 <b>local</b> 语句，它都会定义新的局部变量。
    考虑下面示例：

    <pre>
     a = {}
     local x = 20
     for i = 1, 10 do
       local y = 0
       a[i] = function () y = y + 1; return x + y end
     end
</pre>
    <p />
    这个循环创建了十个闭包(十个匿名函数实例)。
    每个闭包使用了不同的 <code>y</code> 变量，但是它们共享了同样的 <code>x</code>。

    <h1>4 &ndash; <a name="4">应用编程接口(API)</a></h1>

    <p />
    这一章描述了 Lua 的 C&nbsp;API，也就是可用于 宿主程序 与 Lua 通信的 C&nbsp; 函数。
    所有的 API 函数和相关类型以及常量都在头文件 <a name="pdf-lua.h"><code>lua.h</code></a> 中声明。

    <p />
    尽管我们称之为“函数”，API 中的所有功能也可能是通过宏的形式提供。
    除非特别声明，所有的宏都只会使用一次它们的参数。
    (除非第一个参数，它总是 Lua 状态机)，因此它们不会产生任何隐式的副作用。

    <p />
    与大多数 C 库一样， Lua API 函数不会检查其参数的有效性和一致性。
    然后，你可以通过定义 <a name="pdf-LUA_USE_APICHECK"><code>LUA_USE_APICHECK</code></a> 宏来编译 Lua 以改变这种行为。

    <p />
    Lua 库是完全可重入的：它没有全局变量。
    它将所有需要的信息保存在一个称为 <em>Lua state(Lua 状态机)</em> 的动态结构中。

    <p />
    每个 Lua 状态机有一个或多个线程，这些线程对应于独立的、合作式的执行线。
    类型 <a href="#lua_State"><code>lua_State</code></a>(尽管它的名字称为状态)指向一个线程。
    (间接地，通过线程，它也引用与线程关联的 Lua 状态机。)

    <p />
    除了 <a href="#lua_newstate"><code>lua_newstate</code></a>(它创建一个新的 Lua 状态机，并且返回一个指向这个新状态中的 <em>主线程</em> 的指针)，
    库中的所用函数的第一个参数都是一个指向线程的指针。

    <h2>4.1 &ndash; <a name="4.1">栈</a></h2>

    <p />
    Lua 使用一个 <em>虚拟栈</em> 来与 C 进行值传递。
    栈中的每个元素都代表一个 Lua 值(<b>nil</b>, number, string, 等等)。
    API 中的函数可以通过它们接收到的 Lua 状态机来访问栈。

    <p />
    无论何时 Lua 调用 C，被调用的函数都得到一个新的栈，这个栈独立于 C 函数本身的栈，也独立于之前的 Lua 栈。
    这个栈先包含所有传递给 C 函数的参数，然后这个 C 函数会存储临时的 Lua 值，并且将它需要返回的结果压入栈中返回给调用者。(参见 <a
        href="#lua_CFunction"><code>lua_CFunction</code></a>)

    <p />
    为了方便起见，API 中的所有查询操作没有严格遵循栈的操作规则。
    取而代之的是，它们能通过一个 <em>索引</em> 来访问栈中的任何元素。
    一个正索引表示一个绝对的栈位置，栈底从&nbsp;1 开始；
    一个负索引表示一个相对于栈顶的偏移量。
    换句话说，如果栈有 <em>n</em> 个元素，那么索引&nbsp;1 表示第一个元素(也就是栈中最先被压入的元素)</em>，
    索引 <em>n</em> 表示最后一个元素(也就是栈中最后被压入的元素)；
    索引&nbsp;-1 表示最后一个元素；
    索引 <em>-n</em> 表示第一个元素。

    <h3>4.1.1 &ndash; <a name="4.1.1">栈大小</a></h3>

    <p />
    当你使用 Lua API 进行交互时，你有责任保证调用的一致性。
    特别是，你必须控制栈溢出。
    当你调用任何 API 函数时，你必须确保栈有足够的空间来容纳结果。

    <p />
    这有一个例外：
    当你调用一个没有准确结果个数的 Lua 函数(参见 <a href="#lua_call"><code>lua_call</code></a>)时，
    Lua 确保栈有足够的空间来容纳所有结果。
    然而，它并不保证还有额外的空间。
    因此，在调用之后，在栈上放置任何东西之前，
    你应该使用 <a href="#lua_checkstack"><code>lua_checkstack</code></a> 来确保栈有足够的空间。

    <p />
    不论何时 Lua 调用 C，
    它保证栈至少能容纳 <a name="pdf-LUA_MINSTACK"><code>LUA_MINSTACK</code></a> 个元素；
    也就是说，你可以安全地将 <code>LUA_MINSTACK</code> 个值压入栈中。
    <code>LUA_MINSTACK</code> 定义为 20，
    所以通常你不需要担心栈空间，除非你的代码有循环将元素压入栈中。
    当需要时，你可以使用 <a href="#lua_checkstack"><code>lua_checkstack</code></a> 来确保栈有足够空间以压入新的元素。

    <h3>4.1.2 &ndash; <a name="4.1.2">有效索引和可接受索引</a></h3>

    <p />
    API 中的所有函数都接收一个索引，它必须是 <em>有效索引</em> 或 <em>可接受索引</em>。

    <p />
    <em>有效索引</em> 是指向存储可修改的 Lua 值的位置的索引(1 至栈顶之间的的栈索引(<code>1 &le; abs(index) &le; top</code>)) 和 <em>伪索引</em>(一些可在 C 代码中访问，但是不在栈上的索引)。
    伪索引用于访问注册表(参见 <a href="#4.3">&sect;4.3</a>)和 C 函数的上值。(参见 <a href="#4.2">&sect;4.2</a>)

    <p />
    对于只需要值而不需要指定栈位置的函数(例如，查询函数)，能够通过一个可接受索引来调用。
    一个 <em>可接受索引</em> 是任何有效索引，或者是一个正索引，它在栈顶之后，并且在栈分配的空间内，也就是说，这个索引最大可以为栈大小。
    (注意，0永远不会是一个可接受索引)
    对于 C 函数的上值(参见 <a href="#4.2">&sect;4.2</a>)索引，大于当前 C&nbsp;函数的上值的真实数量也是一个可接受索引，但是无效。
    除非另有说明，API 中的函数都使用可接受索引。

    <p />
    可接受索引用于在查询堆栈时避免针对栈顶部的额外测试。
    例如，一个 C 函数可以查询它的第三个参数，而不需要检查第三个参数是否存在，
    也就是说，不需要检查 3 是否是一个有效索引。

    <p />
    对于可以使用可接受索引调用的函数，所有无效索引都被视为包含一个虚拟类型 <a name="pdf-LUA_TNONE"><code>LUA_TNONE</code></a> 的值，其行为和 nil 值相似。

    <h3>4.1.3 &ndash; <a name="4.1.3">字符串指针</a></h3>

    <p />
    API 中的部分函数返回指向栈中的 Lua 字符串的指针(<code>const char*</code>)。
    (参见 <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>,
    <a href="#lua_pushlstring"><code>lua_pushlstring</code></a>,
    <a href="#lua_pushstring"><code>lua_pushstring</code></a> 和
    <a href="#lua_tolstring"><code>lua_tolstring</code></a>。
    辅助库中的 <a href="#luaL_checklstring"><code>luaL_checklstring</code></a>,
    <a href="#luaL_checkstring"><code>luaL_checkstring</code></a>
    和 <a href="#luaL_tolstring"><code>luaL_tolstring</code></a>)。

    <p />
    通常，Lua 的垃圾收集能够释放或移动内部内存从而使指向内部字符串的指针失效。
    为了安全地使用这些指针，API 保证字符串值在没有从栈中移除的情况下，栈中的任何字符串指针都是有效的。
    (尽管它可能会被移动到其它索引)
    当索引是一个伪索引(指向一个上值)时，只要相应的调用还是活跃的并且对应上值没有被修改，那么这个指针就是有效的。

    <p />
    调试接口中也有一些函数返回指向字符串的指针，
    它们是 <a href="#lua_getlocal"><code>lua_getlocal</code></a>,
    <a href="#lua_getupvalue"><code>lua_getupvalue</code></a>,
    <a href="#lua_setlocal"><code>lua_setlocal</code></a> 和
    <a href="#lua_setupvalue"><code>lua_setupvalue</code></a>。
    对于这些函数，这些指针在调用函数处于活跃状态并且给定闭包(如果有)在栈上时，指针被保证是有效的。

    <p />
    除这些保证外，垃圾收集器将释放指向内部字符串的指针以使其无效。

    <h2>4.2 &ndash; <a name="4.2">C 闭包</a></h2>

    <p />
    当一个 C 函数被创建，它可能会与一些值相关联，以这种方式创建的就是一个 <em>C 闭包</em>
    (参见 <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a>);
    这些值称为 <em>上值</em>，不论何时函数被调用，该函数都可以访问这些值。

    <p />
    不论何时一个 C 函数被调用，它的上值都存放在特定的伪索引上。
    这些伪索引通过宏 <a href="#lua_upvalueindex"><code>lua_upvalueindex</code></a> 来产生。
    与函数关联的第一个上值在索引 <code>lua_upvalueindex(1)</code>，以此类推。
    大于当前函数上值个数的 <em>n</em> 的位置(但是不能大于256，它是一个闭包中上值的最大个数)产生一个可接受但无效的索引。

    <p />
    C 闭包也可以修改它相应的上值的值。

    <h2>4.3 &ndash; <a name="4.3">注册表</a></h2>

    <p />
    Lua 提供了一个 <em>注册表</em>，一个可以被任何 C 代码用来存储它需要的 Lua 值的预定义表。
    注册表总是可以使用伪索引 <a name="pdf-LUA_REGISTRYINDEX"><code>LUA_REGISTRYINDEX</code></a> 来访问。
    任何 C 库都可以将数据存储到这个表中，但必须注意选择与其它库使用的键不同的键，以避免冲突。
    通常，你应该使用一个包含你的库名称的字符串作为键，或你代码中包含的 C 对象地址的轻量用户数据，或你代码中创建的 Lua 对象。
    与变量名一样，以下划线开头后面跟大写字母的字符串键是 Lua 保留的。

    <p />
    注册表中的整数键用于引用机制(参见 <a href="#luaL_ref"><code>luaL_ref</code></a>)和一些预定义值。
    因此，注册表中的整数键一定不能用于其它目的。

    <p />
    当你创建一个 Lua 状态机时，它的注册表会附带一些预定义的值。
    这些预定义值通过整数键来索引，它们作为常量定义在 <code>Lua.h</code> 中。
    定义了以下常量：

    <ul>
        <li><b><a name="pdf-LUA_RIDX_MAINTHREAD"><code>LUA_RIDX_MAINTHREAD</code></a>: </b>
            在注册表的这个索引上是当前状态的主线程。(主线程和状态机是同时被创建出来的)
        </li>

        <li><b><a name="pdf-LUA_RIDX_GLOBALS"><code>LUA_RIDX_GLOBALS</code></a>: </b>
            在注册表的这个索引上是全局环境。
        </li>
    </ul>

    <h2>4.4 &ndash; <a name="4.4">C 中的错误处理</a></h2>

    <p />
    在内部实现中，Lua 使用 C <code>longjmp</code> 机制来处理错误。(如果你使用 C++编译， Lua 将使用异常；在源码中搜索 <code>LuaI_THROW</code> 以了解更多细节)
    当 Lua 面对一个错误时，像内存分配错误和类型错误，它 <em>抛出</em> 一个错误；
    也就是说，它进行一次 <em>长跳转(long jump)</em>。
    一个 <em>受保护的环境</em> 使用 <code>setjmp</code> 来设置一个恢复点；
    任何错误都会跳转到最近的活跃的恢复点。

    <p />
    在 C 函数中，你可以通过显式调用 <a href="#lua_error"><code>lua_error</code></a> 来抛出一个错误。

    <p />
    API 中的大部分操作可以抛出错误，例如，内存分配错误。
    每个函数的文档中都指出了它是否可以抛出错误。

    <p />
    如果在不受保护的环境中发生了一个错误，Lua 调用一个 <em>应急(panic)函数</em> (参见 <a href="#lua_atpanic"><code>lua_atpanic</code></a>)，然后调用
    <code>abort</code>，来退出宿主程序。
    你的应急函数可以通过永远不返回来避免退出。
    (例如，在 Lua 之外进行一次长跳转到自己的恢复点)

    <p />
    应急函数，就像它的名字一样，是最后的手段。
    程序应该避免使用它。
    一般来说，当使用一个 Lua 状态机调用一个 C 函数时，该函数可以在该 Lua 状态机上执行任何操作，因为它应该已经被保护了。
    然而，当 C 代码在其它 Lua 状态机上操作时，
    (例如，函数的 Lua 状态机参数，存储在注册表中的 Lua 状态机，<a href="#lua_newthread"><code>lua_newthread</code></a> 的返回值)，
    它应该只在不能抛出错误的 API 调用中使用它们。

    <p />
    应急函数运行起来就像一个消息处理器(参见 <a href="#2.3">&sect;2.3</a>)，错误对象在栈顶。
    然而，没有保证任何栈空间。
    为了在栈上推送任何东西，应急函数必须首先检查可用空间(参见 <a href="#4.1.1">&sect;4.1.1</a>)。

    <h3>4.4.1 &ndash; <a name="4.4.1">状态码</a></h3>

    <p />
    API 中大多数函数报告错误时使用下面状态码以指示不同类型的错误或其它情况：

    <ul>
        <li><b><a name="pdf-LUA_OK"><code>LUA_OK</code></a> (0): </b> 没有错误。</li>
        <li><b><a name="pdf-LUA_ERRRUN"><code>LUA_ERRRUN</code></a>: </b> 运行时错误。</li>
        <li><b><a name="pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>: </b>内存分配错误。对于这种错误，Lua 不会调用消息处理器。</li>
        <li><b><a name="pdf-LUA_ERRERR"><code>LUA_ERRERR</code></a>: </b> 当运行消息处理器时发生错误。</li>
        <li><b><a name="pdf-LUA_ERRSYNTAX"><code>LUA_ERRSYNTAX</code></a>: </b> 预编译时的语法错误。</li>
        <li><b><a name="pdf-LUA_YIELD"><code>LUA_YIELD</code></a>: </b> 线程(协程)让出。</li>
        <li><b><a name="pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a>: </b>与文件相关的错误；例如，不能打开或读取文件。</li>
    </ul>
    <p />
    这些常量都被定义在头文件 <code>lua.h</code> 中。

    <h2>4.5 &ndash; <a name="4.5">C 中的让出处理</a></h2>

    <p />
    在内部实现中，Lua 使用 C <code>longjmp</code> 机制来处理协程让出。
    因此，如果一个 C 函数 <code>foo</code> 调用了一个 API 函数并且这个 API 函数让出(直接或间接调用了另一个让出的函数)了，
    Lua 不能再返回到 <code>foo</code>，因为 <code>longjmp</code> 移除了 <code>foo</code> 的栈。

    <p />
    为了避免这种问题，当你在 Lua 的 API 调用中尝试让出时，除非使用以下三个函数，
    否则 Lua 会报错：
    <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
    <a href="#lua_callk"><code>lua_callk</code></a>
    和 <a href="#lua_pcallk"><code>lua_pcallk</code></a>。
    所有这些函数接受一个 <em>延续函数(continuation function)</em>
    (作为参数，命名为 <code>k</code>)以在让出之后继续执行。

    <p />
    我们需要一些术语去解释这种延续。
    我们将从 Lua 调用的 C 函数称为 <em>原始函数(original function)</em>。
    这个原始函数调用的上述三个 C API 函数我们称之为 <em>被调函数(callee function)</em>，这个被调函数可以让出当前线程。
    让出发生在被调函数是 <a href="#lua_yieldk"><code>lua_yieldk</code></a>，
    或传入 <a href="#lua_callk"><code>lua_callk</code></a> / <a href="#lua_pcallk"><code>lua_pcallk</code></a> 的函数调用了让出时。

    <p />
    假设正在运行的被调函数让出了执行中的线程。
    当线程再次延续这条线程时，它最终将完成这个被调函数。
    然而，被调函数不能返回到原始函数，因为它在 C 栈上的栈被让出销毁了。
    取而代之的是，Lua 会调用一个 <em>延续函数</em>，这个延续函数作为被调函数的参数传递给它。
    正如其名，这个延续函数应该继续原始函数的任务。

    <p />
    作为示例，考虑下面这个函数：

    <pre>
     int original_function (lua_State *L) {
       ...     /* code 1 */
       status = lua_pcall(L, n, m, h);  /* calls Lua */
       ...     /* code 2 */
     }
</pre>
    <p />
    现在我们想允许被 <a href="#lua_pcall"><code>lua_pcall</code></a> 运行的 Lua 代码让出。
    首先，可以将我们的函数重写成这样：

    <pre>
     int k (lua_State *L, int status, lua_KContext ctx) {
       ...  /* code 2 */
     }

     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcall(L, n, m, h), ctx);
     }
</pre>
    <p />
    上述代码中，新函数 <code>k</code> 是一个 <em>延续函数</em> (类型是 <a href="#lua_KFunction"><code>lua_KFunction</code></a>)，
    它应该完成原始函数调用 <a href="#lua_pcall"><code>lua_pcall</code></a> 后的所有工作。
    现在，我们必须通知 Lua，如果在通过 <a href="#lua_pcall"><code>lua_pcall</code></a> 执行的 Lua 的代码通过一些方法(错误或让出)被中断，它必须调用
    <code>k</code>。
    因此我们这样重写代码，用 <a href="#lua_pcallk"><code>lua_pcallk</code></a> 来替换 <a href="#lua_pcall"><code>lua_pcall</code></a>。

    <pre>
     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
     }
</pre>
    <p />
    这里注意对延续函数的外部显式调用：
    Lua 仅会在需要时，也就是当错误发生或继续一个让出的执行时才会调用延续函数，
    如果被调函数返回正常而没有被让出，那么 <a href="#lua_pcallk"><code>lua_pcallk</code></a> (和 <a
        href="#lua_callk"><code>lua_callk</code></a>) 也会返回正常。
    (当然，在这种情况下，你也可以直接在原始函数中完成相同的工作。)

    <p />
    除了 Lua 状态机，延续函数还包含两个参数：
    调用的最终状态码(<code>status</code>)和传递给 <a href="#lua_pcallk"><code>lua_pcallk</code></a> 的上下文(<code>ctx</code>)。
    Lua 不使用这个上下文，它只将这个值从原始函数传递给延续函数。
    对于 <a href="#lua_pcallk"><code>lua_pcallk</code></a>，这个状态值和 <a href="#lua_pcallk"><code>lua_pcallk</code></a>
    本应返回的值相同，
    但是当被调函数让出时，状态值被修改为 <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a>(而不是<a
        href="#pdf-LUA_OK"><code>LUA_OK</code></a>)。
    对于 <a href="#lua_yieldk"><code>lua_yieldk</code></a> 和 <a href="#lua_callk"><code>lua_callk</code></a>，当 Lua
    调用延续函数时，状态总是 <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a>。
    (当然，对于这两个函数，Lua 不会在错误发生时调用延续函数，因为它们不处理错误。)
    同样，当你使用 <a href="#lua_callk"><code>lua_callk</code></a> 时，你应该用 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>
    作为状态码来调用延续函数。
    (对于 <a href="#lua_yieldk"><code>lua_yieldk</code></a>，几乎没有什么地方需要直接调用延续函数，因为 <a
        href="#lua_yieldk"><code>lua_yieldk</code></a> 本身并不会返回。)

    <p />
    Lua 将延续函数视为原始函数。
    延续函数从原始函数中接收同样的 Lua 栈，
    其状态与被调用函数返回时的状态相同。
    (例如，在 <a href="#lua_callk"><code>lua_callk</code></a> 之后，函数及其参数从堆栈中移除，并替换为调用的结果)
    延续函数也具有相同的上值。
    无论它返回什么，Lua 都会将其视为原始函数的返回。

    <h2>4.6 &ndash; <a name="4.6">函数与类型</a></h2>

    <p />
    这里通过字母顺序列出 C API 中的所有函数和类型。
    每个函数都有这样一个提示：
    <span class="apii">[-o, +p, <em>x</em>]</span>

    <p />
    第一个字段, <code>o</code>,
    表示函数从栈中弹出的元素个数。
    第二个字段, <code>p</code>,
    表示函数将要压入栈中的元素个数。
    (所有函数总是在将它的参数弹出后将结果压入栈中)
    其中的 <code>x|y</code> 表示函数根据具体情况压入(或弹出) <code>x</code> 或 <code>y</code> 个元素；
    <code>?</code> 表示我们无法只通过它的参数来了解它会弹出/压入多少个元素。
    (例如，它们可能取决于栈上有什么)
    第三个字段，表示函数是否可能抛出错误：
    '<code>-</code>' 表示函数永远不会抛出错误;
    '<code>m</code>' 表示函数可能抛出内存溢出的错误;
    '<code>v</code>' 表示函数可能抛出错误文本中解释的错误;
    '<code>e</code>' 表示函数可以运行运行任意 Lua 代码, 不论是直接运行或者通过元方法，因此可能抛出任何错误。

    <hr />
    <h3><a name="lua_absindex"><code>lua_absindex</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>

    <pre>int lua_absindex (lua_State *L, int idx);</pre>

    <p />
    将可接受索引 <code>idx</code> 转换成等效的绝对索引(不需要依赖栈大小的索引)

    <hr>
    <h3><a name="lua_Alloc"><code>lua_Alloc</code></a></h3>
    <pre>typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);</pre>

    <p />
    用于 Lua 状态机的的内存分配函数类型。
    这个分配器函数必须提供一个功能类似于 <code>realloc</code> 但是又不完全一样的函数。
    它的参数是 <code>ud</code>, 一个传递给 <a href="#lua_newstate"><code>lua_newstate</code></a> 的指针；
    <code>ptr</code>, 一个指向需要被 分配(allocated)/重新分配(reallocated)/释放(freed) 的内存块指针;
    <code>osize</code>, 内存块的原尺寸或关于什么将被分配出来的代码和 <code>nsize</code>, 块的新尺寸。

    <p />
    当 <code>ptr</code> 不为 <code>NULL</code> 时,<code>osize</code> 是指向 <code>ptr</code> 的块的尺寸，即在分配或重新分配时的尺寸。

    <p />
    当 <code>ptr</code> 为 <code>NULL</code> 时，<code>osize</code> 编码 Lua 正在分配的对象的类型。
    当(且仅当) Lua 创建一个对应类型的新对象时，<code>osize</code> 是
    <a href="#pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>,
    <a href="#pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>,
    <a href="#pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>,
    <a href="#pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>,
    <a href="#pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a> 中的一个，
    Lua 将创建一个这种类型的新对象。
    当 <code>osize</code> 为其它值时， Lua 将为其它东西分配内存。

    <p />
    Lua 假定分配器函数有如下行为：

    <p />
    当 <code>nsize</code> 为 0 时，分配器必须表现得像一个 <code>free</code> 函数并且返回 <code>NULL</code>。

    <p />
    当 <code>nsize</code> 不为 0 时，分配器必须表现得像一个 <code>realloc</code> 函数。
    特别注意，当且仅当分配器不能完全满足请求时返回 <code>NULL</code>。

    <p />
    这有一个简单的分配器函数实现实例。
    它在辅助库中由 <a href="#luaL_newstate"><code>luaL_newstate</code></a> 使用。

    <pre>
     static void *l_alloc (void *ud, void *ptr, size_t osize,
                                                size_t nsize) {
       (void)ud;  (void)osize;  /* not used */
       if (nsize == 0) {
         free(ptr);
         return NULL;
       }
       else
         return realloc(ptr, nsize);
     }
</pre>
    <p />
    注意在 ISO&nbsp;C 保证了 <code>free(NULL)</code> 不会有任何作用并且 <code>realloc(NULL,size)</code> 等价于 <code>malloc(size)</code>。

    <hr />
    <h3><a name="lua_arith"><code>lua_arith</code></a></h3>
    <p />
    <span class="apii">[-(2|1), +1, <em>e</em>]</span>

    <pre>void lua_arith (lua_State *L, int op);</pre>

    <p />
    对栈上的两个值(或一个值，例如一元负)执行一次数学或位操作，其中栈顶的那个值是第二个操作数，弹出这些值，并且将操作结果压入栈中。
    这个函数遵循 Lua 操作符语义的相关定义(即，可能会调用元方法)。

    <p />
    <code>op</code> 的值必须是下面常量之一:
    <ul>
        <li><b><a name="pdf-LUA_OPADD"><code>LUA_OPADD</code></a>: </b> 加法 (<code>+</code>)</li>
        <li><b><a name="pdf-LUA_OPSUB"><code>LUA_OPSUB</code></a>: </b> 减法(<code>-</code>)</li>
        <li><b><a name="pdf-LUA_OPMUL"><code>LUA_OPMUL</code></a>: </b> 乘法 (<code>*</code>)</li>
        <li><b><a name="pdf-LUA_OPDIV"><code>LUA_OPDIV</code></a>: </b> 浮点除法 (<code>/</code>)</li>
        <li><b><a name="pdf-LUA_OPIDIV"><code>LUA_OPIDIV</code></a>: </b> 向下取整除法 (<code>//</code>)</li>
        <li><b><a name="pdf-LUA_OPMOD"><code>LUA_OPMOD</code></a>: </b> 取模 (<code>%</code>)</li>
        <li><b><a name="pdf-LUA_OPPOW"><code>LUA_OPPOW</code></a>: </b> 乘方 (<code>^</code>)</li>
        <li><b><a name="pdf-LUA_OPUNM"><code>LUA_OPUNM</code></a>: </b> 取负 (一元 <code>-</code>)</li>
        <li><b><a name="pdf-LUA_OPBNOT"><code>LUA_OPBNOT</code></a>: </b> 按位取反 (<code>~</code>)</li>
        <li><b><a name="pdf-LUA_OPBAND"><code>LUA_OPBAND</code></a>: </b> 按位与 (<code>&amp;</code>)</li>
        <li><b><a name="pdf-LUA_OPBOR"><code>LUA_OPBOR</code></a>: </b> 按位或 (<code>|</code>)</li>
        <li><b><a name="pdf-LUA_OPBXOR"><code>LUA_OPBXOR</code></a>: </b> 按位异或 (<code>~</code>)</li>
        <li><b><a name="pdf-LUA_OPSHL"><code>LUA_OPSHL</code></a>: </b> 左移 (<code>&lt;&lt;</code>) </li>
        <li><b><a name="pdf-LUA_OPSHR"><code>LUA_OPSHR</code></a>: </b> 右移 (<code>&gt;&gt;</code>)</li>
    </ul>

    <hr />
    <h3><a name="lua_atpanic"><code>lua_atpanic</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);</pre>

    <p />
    设置一个新的应急函数并且返回旧的那个 (参见 <a href="#4.4">&sect;4.4</a>)。

    <hr />
    <h3><a name="lua_call"><code>lua_call</code></a></h3>
    <p />
    <span class="apii">[-(nargs+1), +nresults, <em>e</em>]</span>
    <pre>void lua_call (lua_State *L, int nargs, int nresults);</pre>

    <p />
    调用一个函数。和其它常规 Lua 调用一样，<code>lua_call</code> 会触发 <code>__call</code> 元方法， 因此，这里的 "函数" 指任何可调用值。

    <p />
    调用必须遵循以下规则：
    首先，被调用函数被压入栈中；
    然后，将函数参数正序压入栈(第一个函参数最先压入)；
    最后，调用 <a href="#lua_call"><code>lua_call</code></a>；
    <code>nargs</code> 是你压入栈中的参数个数。
    当一个参数返回时，所有的参数和被调用函数都将弹出，返回值被压入栈中。
    返回值将被调整为 <code>nresults</code> 个，除非 <code>nresults</code> 为 <a name="pdf-LUA_MULTRET"><code>LUA_MULTRET</code></a>。
    在这种情况下，所有返回值都将被压入栈中，Lua 负责确保这些返回值在栈空间，但它不会保证栈空间中有额外的空间。
    函数返回值以正序压入栈中(第一个返回值最先压入)。
    因此，调用之后，最后的返回值在栈顶。

    <p />
    函数调用和运行过程中的所有错误都将被向上传播(通过一个 <code>longjmp</code>)。

    <p />
    下面示例展示了如何在主机程序中实现一个等价的 Lua 代码：

    <pre>
     a = f("how", t.x, 14)
</pre>
    <p />
    C 代码:

    <pre>
     lua_getglobal(L, "f");                  /* function to be called */
     lua_pushliteral(L, "how");                       /* 1st argument */
     lua_getglobal(L, "t");                    /* table to be indexed */
     lua_getfield(L, -1, "x");        /* push result of t.x (2nd arg) */
     lua_remove(L, -2);                  /* remove 't' from the stack */
     lua_pushinteger(L, 14);                          /* 3rd argument */
     lua_call(L, 3, 1);     /* call 'f' with 3 arguments and 1 result */
     lua_setglobal(L, "a");                         /* set global 'a' */
</pre>
    <p />
    注意这段代码是 <em>平衡的</em>；到了最后，堆栈恢复成了调用前的样子。这是一种良好的变成习惯。

    <hr />
    <h3><a name="lua_callk"><code>lua_callk</code></a></h3>
    <p />
    <span class="apii">[-(nargs + 1), +nresults, <em>e</em>]</span>
    <pre>void lua_callk (lua_State *L,
                int nargs,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);</pre>

    <p />
    这个函数的行为和 <a href="#lua_call"><code>lua_call</code></a> 完全一致, 但是允许被调用函数让出(参见 <a href="#4.5">&sect;4.5</a>)。

    <hr />
    <h3><a name="lua_CFunction"><code>lua_CFunction</code></a></h3>
    <pre>typedef int (*lua_CFunction) (lua_State *L);</pre>

    <p />
    C 函数类型。

    <p />
    为了与 Lua 正确的进行交互，一个 C 函数必须使用下面的规则，这些规则定义了参数和返回值的传递方法：
    一个 C 函数从 Lua 栈中以正序接收参数(第一个参数最先入栈)。
    因此，当一个函数开始时，<code>lua_gettop(L)</code> 返回函数接收到的参数个数。
    第一个参数(如果有)的索引为 1，最后一个参数的索引为 <code>lua_gettop(L)</code>。
    为了返回值给 Lua， C 函数只需要将它们以正序(第一个返回值最先入栈)压入栈中，然后在 C 中返回结果的个数。
    这些返回值下的其它值都将被 Lua 丢弃。
    这样，Lua 中调用的 C 函数就可以像一个 Lua 函数那样返回多个返回值。

    <p />
    例如，下面的函数接收一个可变数量的数值参数，并返回它们的平均值和总和:

    <pre>
     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* number of arguments */
       lua_Number sum = 0.0;
       int i;
       for (i = 1; i &lt;= n; i++) {
         if (!lua_isnumber(L, i)) {
           lua_pushliteral(L, "incorrect argument");
           lua_error(L);
         }
         sum += lua_tonumber(L, i);
       }
       lua_pushnumber(L, sum/n);        /* first result */
       lua_pushnumber(L, sum);         /* second result */
       return 2;                   /* number of results */
     }
</pre>

    <hr />
    <h3><a name="lua_checkstack"><code>lua_checkstack</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_checkstack (lua_State *L, int n);</pre>

    <p />
    确保栈中有空间容纳至少有 <code>n</code> 个额外元素。
    也就是说，你能够安全地压入 <code>n</code> 个值。
    如果不能完全满足这个请求，它将返回 false，失败原因包括把栈扩大到比最大尺寸还大(至少几千个元素)或分配内存失败。
    这个函数永远不会缩小栈；
    如果栈已经有足够的空间，它不会做任何改变。

    <hr />
    <h3><a name="lua_close"><code>lua_close</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_close (lua_State *L);</pre>

    <p />
    关闭主线程中所有活动的待关闭变量，释放给定 Lua 状态机中的所有对象(如果有对应的 gc 原函数，将调用它们)并且释放用于这个状态的所有动态资源。

    <p />
    在一些平台上，你不必调用这个函数，因为当宿主程序结束时，所有的资源自然就被释放了。
    另一方面，长期运行的程序，比如守护程序和 web 服务器，它们可能创键多个状态机，可能需要在它们不再被需要时关闭对应的状态机。

    <hr />
    <h3><a name="lua_closeslot"><code>lua_closeslot</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>e</em>]</span>
    <pre>void lua_closeslot (lua_State *L, int index);</pre>

    <p />
    关闭给定 index 索引的待关闭变量并且将其值设置为 <b>nil</b>。
    索引必须是之前标记为要关闭的最后一个索引(参见 <a href="#lua_toclose"><code>lua_toclose</code></a>)，并且仍然是活动的(即还没有关闭)。

    <p />
    当调用这个函数时， <code>__close</code> 元方法不能让出。

    <p />
    该函数在 5.4.3 版中引入。

    <hr />
    <h3><a name="lua_closethread"><code>lua_closethread</code></a></h3>
    <p />
    <span class="apii">[-0, +?, &ndash;]</span>
    <pre>int lua_closethread (lua_State *L, lua_State *from);</pre>

    <p />
    重置一个线程，清空它的调用栈并且关闭待处理的待关闭变量。
    返回一个状态码：线程没有错误(包括停止线程的原始错误和关闭方法中的错误)时返回 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>，或其它状态下的错误码。
    发生错误时，将错误对象放在栈顶。

    <p />
    <code>from</code> 参数表示正在重置的 <code>L</code> 的协程。
    如果没有这种协程，这个参数可以是一个 <code>NULL</code>。

    <p />
    该函数在 5.4.6 版中引入。

    <hr />
    <h3><a name="lua_compare"><code>lua_compare</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>e</em>]</span>
    <pre>int lua_compare (lua_State *L, int index1, int index2, int op);</pre>

    <p />
    比较两个 Lua 值。
    当索引 <code>index1</code> 处的值通过 <code>op</code>
    和索引 <code>index2</code> 处的值做比较后条件满足，函数返回 1 。
    这个函数遵循 Lua 对应的操作规则(即有可能触发元方法)。
    反之，函数返回 0。
    当任何一个索引无效时，函数也会返回 0 。

    <p />
    <code>op</code> 的值必须是下面常量之一。
    <ul>
        <li><b><a name="pdf-LUA_OPEQ"><code>LUA_OPEQ</code></a>: </b> 相等比较(<code>==</code>)</li>
        <li><b><a name="pdf-LUA_OPLT"><code>LUA_OPLT</code></a>: </b> 小于比较(<code>&lt;</code>)</li>
        <li><b><a name="pdf-LUA_OPLE"><code>LUA_OPLE</code></a>: </b> 小于等于比较(<code>&lt;=</code>)</li>
    </ul>

    <hr />
    <h3><a name="lua_concat"><code>lua_concat</code></a></h3>
    <p />
    <span class="apii">[-n, +1, <em>e</em>]</span>
    <pre>void lua_concat (lua_State *L, int n);</pre>

    <p />
    连接栈顶的 <code>n</code> 个值，弹出它们，并且将结果放在栈顶。
    如果 <code>n</code> 为1，结果就是栈顶的那个值，(也就是说，函数什么都不做)；
    如果 <code>n</code> 为0，结果是一个空字符串。
    连接操作按照 Lua 常用语义下的规则进行。(参见 <a href="#3.4.6">&sect;3.4.6</a>).

    <hr />
    <h3><a name="lua_copy"><code>lua_copy</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_copy (lua_State *L, int fromidx, int toidx);</pre>

    <p />
    将 <code>fromidx</code> 索引处的元素复制到有效索引 <code>toidx</code>，替换其值。其它地方的值不会受到影响。

    <hr />
    <h3><a name="lua_createtable"><code>lua_createtable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void lua_createtable (lua_State *L, int narr, int nrec);</pre>

    <p />
    创建一个空表并且将其压入栈中。
    参数 <code>narr</code> 是表将包含多少个元素作为序列的提示。
    参数 <code>nrec</code> 是表将包含多少个其它元素的提示。
    Lua 可能用这些提示来为新表预分配内存。
    当你提前知道这个表将包含多少个元素时，这种预分配将提升性能。
    否则，你可以使用函数 <a href="#lua_newtable"><code>lua_newtable</code></a>。

    <hr />
    <h3><a name="lua_dump"><code>lua_dump</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_dump (lua_State *L,
                        lua_Writer writer,
                        void *data,
                        int strip);</pre>

    <p />
    将函数导出成二进制块。
    接收栈顶的 Lua 函数，并将其转换成一个二进制块，
    该块可以被加载回来，将产生一个等价于被转换函数的函数。
    当它生成块的一部分时，<a href="#lua_dump"><code>lua_dump</code></a> 通过调用给定的 <code>data</code> 来
    调用 <code>writer</code>(参见 <a href="#lua_Writer"><code>lua_Writer</code></a>) 以写入它们。

    <p />
    如果 <code>strip</code> 为 true，
    那么二进制块将不会包含关于函数的调试信息，以节省空间。

    <p />
    返回值是最后一次调用 <code>writer</code> 时的错误码；
    0&nbsp;表示没有错误。

    <p />
    这个函数不会将 Lua 函数从栈中弹出。

    <hr />
    <h3><a name="lua_error"><code>lua_error</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>v</em>]</span>
    <pre>int lua_error (lua_State *L);</pre>

    <p />
    将栈顶的值作为错误函数，抛出一个 Lua 错误，
    这个函数使用 long jump, 因此永远不会返回 (参见 <a href="#luaL_error"><code>luaL_error</code></a>)。

    <hr />
    <h3><a name="lua_gc"><code>lua_gc</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_gc (lua_State *L, int what, ...);</pre>

    <p />
    控制垃圾收集器(GC)。

    <p />
    这个函数根据参数 <codw>what</codw> 执行不同的任务。
    对于需要额外参数的选项，它们讲被列在选项之后。
    <ul>
        <li><b><code>LUA_GCCOLLECT</code>: </b>执行一次完整的GC。</li>
        <li><b><code>LUA_GCSTOP</code>: </b>停止垃圾收集。</li>
        <li><b><code>LUA_GCRESTART</code>: </b>重启垃圾收集。</li>
        <li><b><code>LUA_GCCOUNT</code>: </b>返回 Lua 中当前使用的总内存(单位: K 字节)</li>
        <li><b><code>LUA_GCCOUNTB</code>: </b>返回当前内存使用量除以 1024 的余数。</li>
        <li><b><code>LUA_GCSTEP</code> <code>(int stepsize)</code>: </b>执行一个对应内存 <code>stepsize</code> 的增量垃圾收集步骤。</li>
        <li><b><code>LUA_GCISRUNNING</code>: </b>返回收集器是否在运行(即没有停止)。</li>
        <li><b><code>LUA_GCINC</code> (int pause, int stepmul, int stepsize): </b>
            通过给定参数更改垃圾收集模式为增量模式(参见 <a href="#2.5.1">&sect;2.5.1</a>)。
            返回之前的模式(<code>LUA_GCGEN</code> 或 <code>LUA_GCINC</code>)。
        </li>
        <li><b><code>LUA_GCGEN</code> (int minormul, int majormul): </b>
            通过给定参数将更改垃圾收集模式为分代模式(参见 <a href="#2.5.2">&sect;2.5.2</a>)。
            返回之前的模式(<code>LUA_GCGEN</code> 或 <code>LUA_GCINC</code>)。
        </li>
    </ul>
    <p />
    关于这些选项的更多细节参见 <a href="#pdf-collectgarbage"><code>collectgarbage</code></a>.

    <p />
    这个函数不应该被终结器调用。

    <hr />
    <h3><a name="lua_getallocf"><code>lua_getallocf</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Alloc lua_getallocf (lua_State *L, void **ud);</pre>

    <p />
    返回给定状态机的内存分配函数，如果 <code>ud</code> 不为 <code>NULL</code>，
    Lua 把设置内存分配的器函数时给出的不透明指针存储在 <code>*ud</code> 中。

    <hr />
    <h3><a name="lua_getfield"><code>lua_getfield</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>int lua_getfield (lua_State *L, int index, const char *k);</pre>

    <p />
    将值 <code>t[k]</code> 压入栈中，<code>t</code> 在 index 处。
    和在 Lua 里一样，这个函数可能会触发对应 "index" 事件的元方法(参见 <a href="#2.4">&sect;2.4</a>)。

    <p />
    返回压入值的类型。

    <hr />
    <h3><a name="lua_getextraspace"><code>lua_getextraspace</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void *lua_getextraspace (lua_State *L);</pre>

    <p />
    返回一个指向与给定 Lua 状态机相关联的内存块指针。
    应用程序能把这块内存用于任何用途；
    Lua 不会使用它。

    <p>
        每一个新线程都会携带一块内存，
        初始化为主线程的这块内存的副本。

        <p />
        默认，这些内存块的大小和空指针大小一致。
        但是你可以通过不同大小来重新编译 Lua 以使用不同的内存块大小。
        (参见 <code>luaconf.h</code> 中的 <code>LUA_EXTRASPACE</code>)

        <hr />
    <h3><a name="lua_getglobal"><code>lua_getglobal</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>int lua_getglobal (lua_State *L, const char *name);</pre>

    <p />
    将全局变量 <code>name</code> 的值压入栈，返回该值的类型。

    <hr />
    <h3><a name="lua_geti"><code>lua_geti</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>int lua_geti (lua_State *L, int index, lua_Integer i);</pre>

    <p />
    将 <code>t[i]</code> 的值压入栈。<code>t</code> 在 index 处。
    和在 Lua 里一样，这个函数可能会触发 "index" 事件的元方法(参见 <a href="#2.4">&sect;2.4</a>)。

    <p />
    返回压入值的类型。

    <hr />
    <h3><a name="lua_getmetatable"><code>lua_getmetatable</code></a></h3>
    <p />
    <span class="apii">[-0, +(0|1), &ndash;]</span>
    <pre>int lua_getmetatable (lua_State *L, int index);</pre>

    <p />
    如果 index 处的值有元表，函数将该元表压入栈并且返回 1，否则，函数返回 0 并且不会将任何值压入栈。

    <hr />
    <h3><a name="lua_gettable"><code>lua_gettable</code></a></h3>
    <p />
    <span class="apii">[-1, +1, <em>e</em>]</span>
    <pre>int lua_gettable (lua_State *L, int index);</pre>

    <p />
    将 <code>t[k]</code> 压入栈中，<code>t</code> 是 index 处的值，<code>k</code> 是栈顶的值。

    <p />
    这个函数将键从栈中弹出，将结果值压入它的位置。
    和在 Lua 里一样，这个函数可能会触发 "index" 事件的元方法(参见 <a href="#2.4">&sect;2.4</a>)。

    <p />
    返回压入值的类型。

    <hr />
    <h3><a name="lua_gettop"><code>lua_gettop</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_gettop (lua_State *L);</pre>

    <p />
    返回栈顶元素的索引。
    因为索引从 1 开始，这个结果也等于占的个数。
    特别地，0 意味着是一个空栈。

    <hr />
    <h3><a name="lua_getiuservalue"><code>lua_getiuservalue</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int lua_getiuservalue (lua_State *L, int index, int n);</pre>

    <p />
    将与 index 处的用户数据相关联的第 <code>n</code> 个用户值压入栈。
    返回压入值的类型。

    <p />
    如果用户数据没有对应值，将压入 <b>nil</b> 并且返回 <a href="#pdf-LUA_TNONE"><code>LUA_TNONE</code></a>。

    <hr />
    <h3><a name="lua_insert"><code>lua_insert</code></a></h3>
    <p />
    <span class="apii">[-1, +1, &ndash;]</span>
    <pre>void lua_insert (lua_State *L, int index);</pre>

    <p />
    将栈顶元素移动到给定有效索引，依次移动这个索引上的元素。
    这个函数不能接受伪索引，因为伪索引并没有真实地存在于栈中。

    <hr />
    <h3><a name="lua_Integer"><code>lua_Integer</code></a></h3>
    <pre>typedef ... lua_Integer;</pre>

    <p />
    Lua 的整数类型。

    <p />
    默认这个类型是 <code>long long</code>,(通常是一个 64 位以二进制补码整数)，
    但是可以修改为 <code>long</code> 或 <code>int</code>(通常是一个 32位的二进制补码整数)
    (参见 <code>luaconf.h</code> 中的 <code>LUA_INT_TYPE</code>)

    <p />
    Lua 也定义了常量
    <a name="pdf-LUA_MININTEGER"><code>LUA_MININTEGER</code></a> 和 <a
        name="pdf-LUA_MAXINTEGER"><code>LUA_MAXINTEGER</code></a> 以适应类型的最大值和最小值。

    <hr />
    <h3><a name="lua_isboolean"><code>lua_isboolean</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isboolean (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个 <b>boolean</b> 值则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_iscfunction"><code>lua_iscfunction</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_iscfunction (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个 C 函数则返回 1，否则返回 0。


    <hr />
    <h3><a name="lua_isfunction"><code>lua_isfunction</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isfunction (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个函数(不论 C 还是 Lua) 则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isinteger"><code>lua_isinteger</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isinteger (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个整数值(值是一个数字且可以用整数表示)则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_islightuserdata"><code>lua_islightuserdata</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_islightuserdata (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个轻量用户数据则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isnil"><code>lua_isnil</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isnil (lua_State *L, int index);</pre>

    <p />
    如果 index 处是 <b>nil</b> 则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isnone"><code>lua_isnone</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isnone (lua_State *L, int index);</pre>

    <p />
    如果 index 无效返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isnoneornil"><code>lua_isnoneornil</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isnoneornil (lua_State *L, int index);</pre>

    <p />
    如果 index 无效或值为 <b>nil</b> 则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isnumber"><code>lua_isnumber</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isnumber (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个数字或一个可以转换为数字的字符串则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isstring"><code>lua_isstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isstring (lua_State *L, int index);</pre>

    <p />
    如果 index 处是一个字符串或数字(总是可以转换为字符串)则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_istable"><code>lua_istable</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_istable (lua_State *L, int index);</pre>

    <p />
    如果 index 处是表则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isthread"><code>lua_isthread</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isthread (lua_State *L, int index);</pre>

    <p />
    如果 index 处是线程则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isuserdata"><code>lua_isuserdata</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isuserdata (lua_State *L, int index);</pre>

    <p />
    如果 index 处是用户数据(不论是完全还是轻量)则返回 1，否则返回 0。

    <hr />
    <h3><a name="lua_isyieldable"><code>lua_isyieldable</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_isyieldable (lua_State *L);</pre>

    <p />
    如果给定的协程可以让出，返回 1 ，否则返回 0 。

    <hr />
    <h3><a name="lua_KContext"><code>lua_KContext</code></a></h3>
    <pre>typedef ... lua_KContext;</pre>

    <p />
    可延续函数上下文类型。
    它必须是一个数字类型。
    当 <code>intptr_t</code> 可用时它被定义为 <code>intptr_t</code>，
    因此它也可以存储指针。
    否则，它使用 <code>ptrdiff_t</code>来定义。

    <hr />
    <h3><a name="lua_KFunction"><code>lua_KFunction</code></a></h3>
    <pre>typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);</pre>

    <p />
    延续函数类型(参见 <a href="#4.5">&sect;4.5</a>)。

    <hr />
    <h3><a name="lua_len"><code>lua_len</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>void lua_len (lua_State *L, int index);</pre>

    <p />
    返回 index 处值的长度。
    它等价于 Lua 中的 <code>#</code> 操作符 (参见 <a href="#3.4.7">&sect;3.4.7</a>)，
    并且它可能会触发 "length" 事件对应的元方法。(参见 <a href="#2.4">&sect;2.4</a>)。
    结果压入栈中。

    <hr />
    <h3><a name="lua_load"><code>lua_load</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname,
              const char *mode);</pre>

    <p />
    加载一个 Lua 代码块但不运行它。
    如果没有错误，<code>lua_load</code> 将编译后的块作为一个 Lua 函数压入栈。
    否则，将压入错误消息。

    <p />
    <code>lua_load</code> 函数使用一个用户提供的 <code>reader</code> 函数去读取代码块(参见 <a
        href="#lua_Reader"><code>lua_Reader</code></a>)。
    <code>data</code> 参数是传入 reader 函数的一个不透明值。

    <p />
    <code>chunkname</code> 参数设置给定代码块的名字，它将被用于错误消息和调试信息(参见 <a href="#4.7">&sect;4.7</a>)。

    <p />
    <code>lua_load</code> 自动检测代码块是文本还是二进制并且根据情况加载它(参见程序 <code>luac</code>).
    字符串 <code>mode</code> 与 <a href="#pdf-load"><code>load</code></a> 函数中的作用一致, 此外 <code>NULL</code> 值等价于字符串
    "<code>bt</code>".

    <p />
    <code>lua_load</code> 内部会使用栈，因此 reader 函数必须在返回时保证栈没有被改变。

    <p />
    <code>lua_load</code> 可以返回 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>,
    <a href="#pdf-LUA_ERRSYNTAX"><code>LUA_ERRSYNTAX</code></a> 或
    <a href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>。
    函数也可能返回 read 函数抛出的错误对应的其它值(参见 <a href="#4.4.1">&sect;4.4.1</a>)。

    <p />
    如果函数有上值，它的第一个上值被设置存储在注册表(参见 <a href="#4.3">&sect;4.3</a>)的 <code>LUA_RIDX_GLOBALS</code> 索引处的全局环境。
    当加载主代码块时，这个上值是 <code>_ENV</code> 变量(参见 <a href="#2.2">&sect;2.2</a>)。
    其它上值将被初始化为 <b>nil</b>。

    <hr />
    <h3><a name="lua_newstate"><code>lua_newstate</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_State *lua_newstate (lua_Alloc f, void *ud);</pre>

    <p />
    创建一个独立的状态机并且返回它的主线程。
    如果不能创建状态机(由于内存不足)返回 <code>NULL</code>。
    参数 <code>f</code> 是内存分配函数；
    Lua 将通过这个函数(参见 <a href="#lua_Alloc"><code>lua_Alloc</code></a>)完成这个状态机的所有内存分配工作。
    第二个参数 <code>ud</code> 是一个不透明的内存指针，每当 Lua 调用分配器时都将它传入。

    <hr />
    <h3><a name="lua_newtable"><code>lua_newtable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void lua_newtable (lua_State *L);</pre>

    <p />
    创建一个新的空表并将其压入栈
    它等价于 <code>lua_createtable(L, 0, 0)</code>。

    <hr />
    <h3><a name="lua_newthread"><code>lua_newthread</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>lua_State *lua_newthread (lua_State *L);</pre>

    <p />
    创建一个新线程并将其压入栈，返回一个指向新线程的 <a href="#lua_State"><code>lua_State</code></a> 的指针。
    这个函数返回的新线程和原始线程共享全局变量，但是有一个独立的执行栈。

    <p />
    线程和其它 Lua 对象一样，受制于垃圾收集。

    <hr />
    <h3><a name="lua_newuserdatauv"><code>lua_newuserdatauv</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);</pre>

    <p />
    创建一个新的完全用户数据并将其压入栈，其中包含 <code>nuvalue</code> 个关联 Lua 值(称为 <code>user values(用户值)</code>) 加上一个 <code>size</code> 字节的原始内存块
    (用户值可以通过函数 <a href="#lua_setiuservalue"><code>lua_setiuservalue</code></a> 和 <a href="#lua_getiuservalue"><code>lua_getiuservalue</code></a> 来设置和读取)。

    <p />
    函数返回内存块的地址。
    Lua 保证只要用户数据是活的这个地址是就是有效的(参见 <a href="#2.5">&sect;2.5</a>)。
    此外，如果用户数据被终结器标记(参见 <a href="#2.5.3">&sect;2.5.3</a>)，在调用它的终结器之前它的地址是有效的。

    <hr />
    <h3><a name="lua_next"><code>lua_next</code></a></h3>
    <p />
    <span class="apii">[-1, +(2|0), <em>v</em>]</span>
    <pre>int lua_next (lua_State *L, int index);</pre>

    <p />
    从栈中弹出键，并且将 index 处的表中的一个键值(弹出的键的下一对)对压入栈，
    如果表中没有更多的元素，<a href="#lua_next"><code>lua_next</code></a> 返回 0 并且不会弹出任何值。

    <p />
    一个典型的表遍历如下。

    <pre>
     /* table is in the stack at index 't' */
     lua_pushnil(L);  /* first key */
     while (lua_next(L, t) != 0) {
       /* uses 'key' (at index -2) and 'value' (at index -1) */
       printf("%s - %s\n",
              lua_typename(L, lua_type(L, -2)),
              lua_typename(L, lua_type(L, -1)));
       /* removes 'value'; keeps 'key' for next iteration */
       lua_pop(L, 1);
     }
</pre>

    <p />
    当遍历一个表时，应避免在一个键上直接调用 <a href="#lua_tolstring"><code>lua_tolstring</code></a>，
    除非你知道这个键就是一个字符串。
    调用 <a href="#lua_tolstring"><code>lua_tolstring</code></a> 可能改变 index 处的值；
    这可能会时下一次 <a href="#lua_next"><code>lua_next</code></a> 调用产生令人困惑的结果。

    <p />
    如果给定的键为 <b>nil</b> 或不存在于表中的键，函数可能会抛出一个错误。
    参见函数 <a href="#pdf-next"><code>next</code></a> 以了解在遍历过程中修改表的注意事项。

    <hr />
    <h3><a name="lua_Number"><code>lua_Number</code></a></h3>
    <pre>typedef ... lua_Number;</pre>

    <p />
    Lua 中浮点数的类型。

    <p />
    默认这个类型是 double，但是可以修改为 single float 或 long double。
    (参见 <code>LUA_FLOAT_TYPE</code> in <code>luaconf.h</code>.)

    <hr />
    <h3><a name="lua_numbertointeger"><code>lua_numbertointeger</code></a></h3>
    <pre>int lua_numbertointeger (lua_Number n, lua_Integer *p);</pre>

    <p />
    尝试将一个 Lua 浮点数转换成 Lua 整数。
    浮点数 <code>n</code> 必须有整数值。
    如果值在 Lua 整数可表示范围内，将其转换为一个整数赋值给 <code>*p</code>。
    这个宏的结果是一个布尔值，表示转换是否成功。(注意，由于圆整(rounding)的关系，这个范围测试不用此宏很难正确处理)

    <p />
    这个宏可能对它的参数做多次求值。

    <hr />
    <h3><a name="lua_pcall"><code>lua_pcall</code></a></h3>
    <p />
    <span class="apii">[-(nargs + 1), +(nresults|1), &ndash;]</span>
    <pre>int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);</pre>

    <p />
    在保护模式中调用一个函数 (或可调用对象)。

    <p />
    <code>nargs</code> 和 <code>nresults</code> 都拥有和 <a href="#lua_call"><code>lua_call</code></a> 中一样的含义。
    如果整个调用过程中没有错误， <a href="#lua_pcall"><code>lua_pcall</code></a> 的行为和 <a href="#lua_call"><code>lua_call</code></a> 完全一致。
    然而, 如果有错误， <a href="#lua_pcall"><code>lua_pcall</code></a> 将捕获它，压入一个值(错误对象)到栈上，并且返回一个错误码。
    和 <a href="#lua_call"><code>lua_call</code></a> 一样,
    <a href="#lua_pcall"><code>lua_pcall</code></a> 总是从栈上移除被调用函数和它的调用参数。

    <p />
    如果 <code>msgh</code> 为 0, 栈上返回的错误对象和原错误对象完全一致。
    否则，<code>msgh</code> 是一个 <em>消息处理器</em> 的索引(这个索引不能是伪索引)。
    当发生运行时错误时，处理器将通过错误对象调用这个处理器，并且它的返回值将被 <a href="#lua_pcall"><code>lua_pcall</code></a> 作为一个错误对象压入栈。

    <p />
    特别地，消息处理器可以用来向错误对象添加更多调试信息，就像是一个堆栈跟踪。
    这些信息在 <a href="#lua_pcall"><code>lua_pcall</code></a> 返回后，由于栈已经展开，所以收集不到了。

    <p />
    <a href="#lua_pcall"><code>lua_pcall</code></a> 函数返回下面状态码之一：
    <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>, <a href="#pdf-LUA_ERRRUN"><code>LUA_ERRRUN</code></a>, <a
        href="#pdf-LUA_ERRMEM"><code>LUA_ERRMEM</code></a>, <a href="#pdf-LUA_ERRERR"><code>LUA_ERRERR</code></a>。

    <hr />
    <h3><a name="lua_pcallk"><code>lua_pcallk</code></a></h3>
    <p />
    <span class="apii">[-(nargs + 1), +(nresults|1), &ndash;]</span>
    <pre>int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int msgh,
                lua_KContext ctx,
                lua_KFunction k);</pre>

    <p />
    除了允许调用函数让出(参见 <a href="#4.5">&sect;4.5</a>)，这个函数的行为和 <a href="#lua_pcall"><code>lua_pcall</code></a> 一样。

    <hr />
    <h3><a name="lua_pop"><code>lua_pop</code></a></h3>
    <p />
    <span class="apii">[-n, +0, <em>e</em>]</span>
    <pre>void lua_pop (lua_State *L, int n);</pre>

    <p />
    从栈上弹出 <code>n</code> 个元素。
    它是作为宏用 <a href="#lua_settop"><code>lua_settop</code></a> 上实现的。

    <hr />
    <h3><a name="lua_pushboolean"><code>lua_pushboolean</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushboolean (lua_State *L, int b);</pre>

    <p />
    将值 <code>b</code> 作为一个布尔值压入栈。

    <hr />
    <h3><a name="lua_pushcclosure"><code>lua_pushcclosure</code></a></h3>
    <p />
    <span class="apii">[-n, +1, <em>m</em>]</span>
    <pre>void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);</pre>

    <p />
    将一个新的 C 闭包压入栈。
    这个函数接收一个 C 函数指针并将一个 <code>function</code> 类型的 Lua 值压入栈，当调用该值时，调用相应的 C 函数。
    参数 <code>n</code> 表示函数将拥有多少个上值(参见 <a href="#4.2">&sect;4.2</a>)。

    <p />
    任何可以被 Lua 调用的函数都必须遵循正确的协议来接收其参数并返回其结果(参见 <a href="#lua_CFunction"><code>lua_CFunction</code></a>)。

    <p />
    当一个 C 函数被创建，它可以关联一些值，它们称为上值；
    接下来无论函数何时被调用，这些值都可以被这个函数访问到。
    这种关联称为一个 C 闭包(参见 <a href="#4.2">&sect;4.2</a>)。
    为了创建一个 C 闭包，首先，它的上值的初始化值必须被压入栈。
    (当有多个上值时，第一个值最先被压入)。
    然后调用 <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a> 以创建并且将 C 函数压入栈， 通过参数 <code>n</code>
    告知多少个值将被这个函数关联。
    <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a> 也会将这些值从栈上弹出。

    <p />
    <code>n</code> 的最大值为 255。

    <p />
    当 <code>n</code> 为 0 时,函数创建一个<em>轻量 C 函数</em>，它只是一个指向 C 函数的指针。
    这种情况，不会抛出内存错误。

    <hr />
    <h3><a name="lua_pushcfunction"><code>lua_pushcfunction</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre>

    <p />
    将一个 C 函数压入栈。
    这个函数等价于没有上值的 <a href="#lua_pushcclosure"><code>lua_pushcclosure</code></a>。

    <hr />
    <h3><a name="lua_pushfstring"><code>lua_pushfstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>v</em>]</span>
    <pre>const char *lua_pushfstring (lua_State *L, const char *fmt, ...);</pre>

    <p />
    将一个格式化字符串压入栈中，并且返回字符串指针(参见 <a href="#4.1.3">&sect;4.1.3</a>)。
    它就像是 ISO C 里的sprintf，但是有两个关键不同。
    第一，你不必为结果分配空间；
    结果是一个 Lua 字符串并且 Lua 会处理内存分配(并通过垃圾收集器进行回收)。
    第二，转换说明符有很大的限制。
    它没有标识、宽度和精度。
    转换说明符只能够为
    <pre>
    '<code>%%</code>' (插入一个字符 '<code>%</code>'),
    '<code>%s</code>' (插入一个零结尾的字符串，没有大小限制),
    '<code>%f</code>' (插入一个 <a href="#lua_Number"><code>lua_Number</code></a>),
    '<code>%I</code>' (插入一个 <a href="#lua_Integer"><code>lua_Integer</code></a>),
    '<code>%p</code>' (插入一个 指针),
    '<code>%d</code>' (插入一个 <code>int</code>),
    '<code>%c</code>' (插入一个 <code>int</code> 作为单字节字符), 和
    '<code>%U</code>' (插入一个 <code>long int</code> 作为一个 UTF-8 序列)。
    </pre>

    <p />
    这个函数可能由于内存溢出或无效的转换说明符而抛出错误。

    <hr />
    <h3><a name="lua_pushglobaltable"><code>lua_pushglobaltable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushglobaltable (lua_State *L);</pre>

    <p />
    将全局环境压入栈。

    <hr />
    <h3><a name="lua_pushinteger"><code>lua_pushinteger</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushinteger (lua_State *L, lua_Integer n);</pre>

    <p />
    将一个值为 <code>n</code> 的整数压入栈。

    <hr />
    <h3><a name="lua_pushlightuserdata"><code>lua_pushlightuserdata</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushlightuserdata (lua_State *L, void *p);</pre>

    <p />
    将一个轻量用户数据压入栈。

    <p />
    在 Lua 中，用户数据表示 C 值。
    一个 <em>轻量用户数据</em> 表示一个指针，即 <code>void*</code>。
    它是一个值(就像一个数字)：你不需要创建它，它没有单独的元表，并且它不会被收集(因为它从未被创建)。
    一个轻量用户数据等于具有相同 C 地址的任何轻量用户数据。

    <hr />
    <h3><a name="lua_pushliteral"><code>lua_pushliteral</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>const char *lua_pushliteral (lua_State *L, const char *s);</pre>

    <p />
    这个宏等价于 <a href="#lua_pushstring"><code>lua_pushstring</code></a>,
    但是应该只用于 <code>s</code> 是一个字面量字符串时。
    (Lua 可能会优化这种情况)

    <hr />
    <h3><a name="lua_pushlstring"><code>lua_pushlstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>const char *lua_pushlstring (lua_State *L, const char *s, size_t len);</pre>

    <p />
    将 <code>s</code> 所指向的大小为<code>len</code>的字符串压入堆栈。
    Lua 将生成或重用给定字符串的内部副本，因此 <code>s</code> 的内存会在函数返回后被立即释放或重用。
    字符串可以包含任何二进制数据，包括嵌入 0。

    <p />
    返回一个指向内部字符串副本的指针 (参见 <a href="#4.1.3">&sect;4.1.3</a>)。

    <hr />
    <h3><a name="lua_pushnil"><code>lua_pushnil</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushnil (lua_State *L);</pre>

    <p />
    将一个 nil 值压入栈

    <hr />
    <h3><a name="lua_pushnumber"><code>lua_pushnumber</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushnumber (lua_State *L, lua_Number n);</pre>

    <p />
    将一个值为 <code>n</code> 的浮点数压入栈。

    <hr />
    <h3><a name="lua_pushstring"><code>lua_pushstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>const char *lua_pushstring (lua_State *L, const char *s);</pre>

    <p />
    将 <code>s</code> 所指向的零结尾的字符串压入栈。
    Lua 将生成或重用给定字符串的内部副本，因此 <code>s</code> 的内存会在函数返回后被立即释放或重用。

    <p />
    返回一个指向内部字符串副本的指针 (参见 <a href="#4.1.3">&sect;4.1.3</a>)。

    <p />
    如果 <code>s</code> 为 <code>NULL</code>, 压入 <b>nil</b> 并且返回 <code>NULL</code>。

    <hr />
    <h3><a name="lua_pushthread"><code>lua_pushthread</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int lua_pushthread (lua_State *L);</pre>

    <p />
    将 <code>L</code> 表示的线程压入栈。
    如果这个线程是当前状态机的主线程则返回1。

    <hr />
    <h3><a name="lua_pushvalue"><code>lua_pushvalue</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void lua_pushvalue (lua_State *L, int index);</pre>

    <p />
    将 index 处的元素复制一份压入栈。

    <hr />
    <h3><a name="lua_pushvfstring"><code>lua_pushvfstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>v</em>]</span>
    <pre>const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);</pre>

    <p />
    等价于 <a href="#lua_pushfstring"><code>lua_pushfstring</code></a>, 不同的是它接收一个 <code>va_list</code> 而不是可变数量的参数。

    <hr />
    <h3><a name="lua_rawequal"><code>lua_rawequal</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_rawequal (lua_State *L, int index1, int index2);</pre>

    <p />
    如果索引 <code>index1</code> 处的值和索引 <code>index2</code> 处的值原始相等则返回 1(即，不调用 <code>__eq</code> 元方法的相等)，
    否则返回 0。如果任何一个索引无效也返回 0。

    <hr />
    <h3><a name="lua_rawget"><code>lua_rawget</code></a></h3>
    <p />
    <span class="apii">[-1, +1, &ndash;]</span>
    <pre>int lua_rawget (lua_State *L, int index);</pre>

    <p />
    与 <a href="#lua_gettable"><code>lua_gettable</code></a> 类似, 但是做一次原始访问。(即, 不使用元方法)。
    索引 <code>index</code> 处的值必须是一个表。

    <hr />
    <h3><a name="lua_rawgeti"><code>lua_rawgeti</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int lua_rawgeti (lua_State *L, int index, lua_Integer n);</pre>

    <p />
    将值 <code>t[n]</code> 压入栈，<code>t</code> 在 index 处。
    这个访问是原始的，也就是不会使用 <code>__index</code> 元值。

    <p />
    返回压入值的类型。

    <hr />
    <h3><a name="lua_rawgetp"><code>lua_rawgetp</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int lua_rawgetp (lua_State *L, int index, const void *p);</pre>

    <p />
    将值 <code>t[k]</code> 压入栈，<code>t</code> 在 index 处，<code>k</code> 是指针 <code>p</code> 代表的一个轻量用户数据。
    这个访问是原始的，也就是不会使用 <code>__index</code> 元值。

    <p />
    返回压入值的类型。

    <hr />
    <h3><a name="lua_rawlen"><code>lua_rawlen</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Unsigned lua_rawlen (lua_State *L, int index);</pre>

    <p />
    返回 index 处值的原始"长度"：
    对于字符串，为字符串的长度；
    对于表，为不调用元方法的长度操作符('<code>#</code>')的结果；
    对于用户数据，为用户数据分配的内存块大小。
    对于其它值，为 0。

    <hr />
    <h3><a name="lua_rawset"><code>lua_rawset</code></a></h3>
    <p />
    <span class="apii">[-2, +0, <em>m</em>]</span>
    <pre>void lua_rawset (lua_State *L, int index);</pre>

    <p />
    类似于 <a href="#lua_settable"><code>lua_settable</code></a>, 但是只做一次原始访问(即, 不使用元方法)。
    索引 <code>index</code> 处的值必须是一个表。

    <hr />
    <h3><a name="lua_rawseti"><code>lua_rawseti</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>m</em>]</span>
    <pre>void lua_rawseti (lua_State *L, int index, lua_Integer i);</pre>

    <p />
    等价于 <code>t[i] = v</code>, <code>t</code> 是 index 处的值，<code>v</code> 是栈顶的值。

    <p />
    函数将值从栈上弹出，这个赋值是原始的，也就是说，它不会使用 <code>__newindex</code> 元值。

    <hr />
    <h3><a name="lua_rawsetp"><code>lua_rawsetp</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>m</em>]</span>
    <pre>void lua_rawsetp (lua_State *L, int index, const void *p);</pre>

    <p />
    等价于 <code>t[p] = v</code>,<code>t</code> 是 index 处的值，<code>p</code> 是一个轻量级用户数据，而 <code>v</code> 是栈顶的值。

    <p />
    函数将值从栈上弹出，这个赋值是原始的，也就是说，它不会使用 <code>__newindex</code> 元值。

    <hr />
    <h3><a name="lua_Reader"><code>lua_Reader</code></a></h3>
    <pre>typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);</pre>

    <p />
    用于 <a href="#lua_load"><code>lua_load</code></a> 的读取器函数。
    每当 <a href="#lua_load"><code>lua_load</code></a> 需要代码块的另一部分时，它都会使用它的 <code>data</code> 作为参数调用读取器函数。
    读取器必须返回一个指向新代码块的新片段内存块的指针并且设置 <code>size</code> 为该片段的大小。
    读取器必须保证在下一次调用读取器函数前内存块的存活。为了表示代码块的结尾，读取器必须返回 <code>NULL</code> 或设置 <code>size</code> 为 0。
    读取器函数可以返回大于 0 的任意尺寸大小的片段。

    <hr />
    <h3><a name="lua_register"><code>lua_register</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>e</em>]</span>
    <pre>void lua_register (lua_State *L, const char *name, lua_CFunction f);</pre>

    <p />
    设置全局变量 <code>name</code> 的新值为 C 函数 <code>f</code>。
    它定义为一个宏：

    <pre>
     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))
</pre>

    <hr />
    <h3><a name="lua_remove"><code>lua_remove</code></a></h3>
    <p />
    <span class="apii">[-1, +0, &ndash;]</span>
    <pre>void lua_remove (lua_State *L, int index);</pre>

    <p />
    移除在给定有效索引处的元素，向下移动改索引上方的元素来填充空白。
    这个函数不接受伪索引，因为伪索引并没有真实地存在于栈中。

    <hr />
    <h3><a name="lua_replace"><code>lua_replace</code></a></h3>
    <p />
    <span class="apii">[-1, +0, &ndash;]</span>
    <pre>void lua_replace (lua_State *L, int index);</pre>

    <p />
    将栈顶元素移动到指定索引处，而不移动任何元素(替换 index 处的值)然后弹出栈顶元素。

    <hr />
    <h3><a name="lua_resetthread"><code>lua_resetthread</code></a></h3>
    <p />
    <span class="apii">[-0, +?, &ndash;]</span>
    <pre>int lua_resetthread (lua_State *L);</pre>

    <p />
    函数已弃用；它等价于 <code>from</code> 为 <code>NULL</code> 的 <a href="#lua_closethread"><code>lua_closethread</code></a>。

    <hr />
    <h3><a name="lua_resume"><code>lua_resume</code></a></h3>
    <p />
    <span class="apii">[-?, +?, &ndash;]</span>
    <pre>int lua_resume (lua_State *L, lua_State *from, int nargs,
                          int *nresults);</pre>

    <p />
    开始并延续一个在给定线程 <code>L</code> 中的协程。

    <p />
    要启动一个协程，你应该将主函数和所有参数压入到线程的空栈中。
    然后将参数个数 <code>nargs</code> 作为参数调用 <a href="#lua_resume"><code>lua_resume</code></a>。
    这个调用将在协程暂停或完成执行时返回。
    当它返回时， <code>*nresults</code> 被更新，并且栈顶将包含传入给 <a href="#lua_yield"><code>lua_yield</code></a> 或函数体返回的
    <code>*nresults</code> 个值，
    如果协程让出, <a href="#lua_resume"><code>lua_resume</code></a> 返回 <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a>；
    如果协程完成执行并没有错误，返回<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>；
    如果执行出错，返回错误码(参见 <a href="#4.4.1">&sect;4.4.1</a>)。
    出错时，错误对象将在栈顶。

    <p />
    要延续一个协程，你应该从它的栈上将上次让出的 <code>*nresults</code> 个值移除，把传给 <code>yield</code> 作结果的值压栈，
    然后调用 <a href="#lua_resume"><code>lua_resume</code></a>。

    <p />
    参数 <code>from</code> 表示正在延续 <code>L</code> 的协程。
    如果没有这样的协程，该参数可以为 <code>NULL</code>。

    <hr />
    <h3><a name="lua_rotate"><code>lua_rotate</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_rotate (lua_State *L, int idx, int n);</pre>

    <p />
    旋转有效索引 <code>idx</code> 和栈顶之间的栈元素。
    对于正数 <code>n</code> 表示向上旋转 <code>n</code> 个位置，
    对于负数 <code>n</code> 表示向下旋转 <code>-n</code> 个位置。
    <code>n</code> 的绝对值不能大于旋转的元素个数。
    这个函数不能用于伪索引，因为伪索引并没有真实地存在于栈中。

    <hr />
    <h3><a name="lua_setallocf"><code>lua_setallocf</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);</pre>

    <p />
    修改给定状态机的分配器函数为 <code>f</code>，用户数据为 <code>ud</code>。

    <hr />
    <h3><a name="lua_setfield"><code>lua_setfield</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>e</em>]</span>
    <pre>void lua_setfield (lua_State *L, int index, const char *k);</pre>

    <p />
    等价于 <code>t[k] = v</code>, <code>t</code> 是 index 处的值，<code>v</code> 是栈顶的值。

    <p />
    函数弹出栈顶的值，
    和 Lua 中一样，这个方法可能会触发 "newindex" 事件对应的元方法(参见 <a href="#2.4">&sect;2.4</a>)

    <hr />
    <h3><a name="lua_setglobal"><code>lua_setglobal</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>e</em>]</span>
    <pre>void lua_setglobal (lua_State *L, const char *name);</pre>

    <p />
    从栈顶弹出一个值并将其设置为全局变量 <code>name</code> 的新值。

    <hr />
    <h3><a name="lua_seti"><code>lua_seti</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>e</em>]</span>
    <pre>void lua_seti (lua_State *L, int index, lua_Integer n);</pre>

    <p />
    等价于 <code>t[n] = v</code>, <code>t</code> 是 index 处的值，<code>v</code> 是栈顶的值。

    <p />
    函数弹出栈顶的值，
    和 Lua 中一样，这个方法可能会触发 "newindex" 事件对应的元方法(参见 <a href="#2.4">&sect;2.4</a>)

    <hr />
    <h3><a name="lua_setiuservalue"><code>lua_setiuservalue</code></a></h3>
    <p />
    <span class="apii">[-1, +0, &ndash;]</span>
    <pre>int lua_setiuservalue (lua_State *L, int index, int n);</pre>

    <p />
    从栈上弹出一个值并将其设置为与 index 处的用户数据相关联的第 <code>n</code> 个用户值。
    如果用户数据没有该值则返回 0。

    <hr />
    <h3><a name="lua_setmetatable"><code>lua_setmetatable</code></a></h3>
    <p />
    <span class="apii">[-1, +0, &ndash;]</span>
    <pre>int lua_setmetatable (lua_State *L, int index);</pre>

    <p />
    从栈上弹出一个表或 <b>nil</b> 并且将其设置为 index 处值的新元表(<b>nil</b> 表示没有元表)

    <p />
    (由于历史原因, 这个函数返回一个整数，它总是为 1。)

    <hr />
    <h3><a name="lua_settable"><code>lua_settable</code></a></h3>
    <p />
    <span class="apii">[-2, +0, <em>e</em>]</span>
    <pre>void lua_settable (lua_State *L, int index);</pre>

    <p />
    等价于 <code>t[k] = v</code>, <code>t</code> 是 index 处的值，<code>v</code> 是栈顶的值, 而 <code>k</code> 是栈顶的下一个元素的值。

    <p />
    函数把键和值都从栈上弹出。
    和 Lua 中一样，这个方法可能会触发 "newindex" 事件对应的元方法(参见 <a href="#2.4">&sect;2.4</a>)

    <hr />
    <h3><a name="lua_settop"><code>lua_settop</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>e</em>]</span>
    <pre>void lua_settop (lua_State *L, int index);</pre>

    <p />
    接收任意索引或 0，并且将栈顶设置为该索引。
    如果新的栈顶比旧的大，新元素将使用 <b>nil</b> 进行填充。
    如果 <code>index</code> 为 0，那么所有的栈元素都会被移除。

    <p />
    当从堆栈中移除一个被标记为待关闭的索引时，此函数可以运行任意代码。

    <hr />
    <h3><a name="lua_setwarnf"><code>lua_setwarnf</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);</pre>

    <p />
    设置一个用于 Lua 发出警告的警告函数
    (参见 <a href="#lua_WarnFunction"><code>lua_WarnFunction</code></a>)。
    <code>ud</code> 参数设置传入给警告函数的 <code>ud</code> 值。

    <hr />
    <h3><a name="lua_State"><code>lua_State</code></a></h3>
    <pre>typedef struct lua_State lua_State;</pre>

    <p />
    指向线程并间接(通过线程)指向 Lua 解释器的整个状态的不透明结构。
    Lua 库是完全可重入的:它没有全局变量。关于状态机的所有信息都可以通过这个结构访问。

    <p />
    除了从头开始创建 Lua 状态机的 <a href="#lua_newstate"><code>lua_newstate</code></a> 函数，
    每一个库函数的第一个参数都必须是一个指向这个结构体的指针。

    <hr />
    <h3><a name="lua_status"><code>lua_status</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_status (lua_State *L);</pre>

    <p />
    返回线程 <code>L</code> 的状态。

    <p />
    正常的线程状态为 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a>,
    线程完成 <a href="#lua_resume"><code>lua_resume</code></a> 的执行并且有错误时为错误码，
    线程暂停时为 <a href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a>。

    <p />
    只能在状态为 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> 的线程上调用函数。
    可以延续状态为 <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> (以开始一个新协程) 或 <a
        href="#pdf-LUA_YIELD"><code>LUA_YIELD</code></a> 的线程(以延续一个协程)。

    <hr />
    <h3><a name="lua_stringtonumber"><code>lua_stringtonumber</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>size_t lua_stringtonumber (lua_State *L, const char *s);</pre>

    <p />
    将一个 0 结尾的字符串 <code>s</code> 转换为数字，并将转换后的数字压入栈，返回字符串的总大小(即长度+1)。
    这个转换的结果可能是整数也可能是浮点数，这取决于 Lua 的转换词法(参见 <a href="#3.1">&sect;3.1</a>)。
    字符串可以有前置或后置空格和一个符号。
    如果字符串不是一个有效的数字，将返回 0 并且不会压入任何东西。
    (注意，这个结果可以当做一个布尔值，如果转换成功为真)。

    <hr />
    <h3><a name="lua_toboolean"><code>lua_toboolean</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_toboolean (lua_State *L, int index);</pre>

    <p />
    将 index 处的 Lua 值转换为一个 C 布尔值(0 或 1)。
    和 Lua 中的所有检测一样，任何不同于 <b>false</b> 和 <b>nil</b> 的值 <a href="#lua_toboolean"><code>lua_toboolean</code></a> 都将返回 true；
    否则返回 false。
    (如果你想只接受实际的布尔值，使用 <a href="#lua_isboolean"><code>lua_isboolean</code></a> 来检查值的类型。)

    <hr />
    <h3><a name="lua_tocfunction"><code>lua_tocfunction</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_CFunction lua_tocfunction (lua_State *L, int index);</pre>

    <p />
    将 index 处的值转换为一个 C 函数。
    这个值必须是一个 C 函数；
    否则返回 <code>NULL</code>。

    <hr />
    <h3><a name="lua_toclose"><code>lua_toclose</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>m</em>]</span>
    <pre>void lua_toclose (lua_State *L, int index);</pre>

    <p />
    将栈中 index 标记为一个待关闭插槽 (参见 <a href="#3.3.8">&sect;3.3.8</a>)。
    和 Lua 中的待关闭变量一样，栈中这个插槽的值将在它离开作用域时被关闭。
    在这种情况下，在C函数的上下文中，离开作用域意味着正在运行的函数返回到 Lua，
    或者发生错误，或者该插槽通过 <a href="#lua_settop"><code>lua_settop</code></a> 或 <a href="#lua_pop"><code>lua_pop</code></a> 从堆栈中移除，
    或者调用 <a href="#lua_closeslot"><code>lua_closeslot</code></a>。
    除非先前通过 <a href="#lua_closeslot"><code>lua_closeslot</code></a> 被禁用，否则被标记为待关闭的插槽不应被 API 中除 <a href="#lua_settop"><code>lua_settop</code></a> 或 <a href="#lua_pop"><code>lua_pop</code></a> 的其它函数将其从堆栈中移除。

    <p />
    不应该对等于或小于一个活动的待关闭插槽的索引调用此函数。

    <p />
    注意，不论是发生错误还是正常返回，当 <code>__close</code> 元方法运行时，C 栈已经被展开。
    因此调用函数中所有自动的 C 变量声明 (例如，缓冲区) 都将是无效的。

    <hr />
    <h3><a name="lua_tointeger"><code>lua_tointeger</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Integer lua_tointeger (lua_State *L, int index);</pre>

    <p />
    等价于 <code>isnum</code> 为 <code>NULL</code> 的 <a href="#lua_tointegerx"><code>lua_tointegerx</code></a>。

    <hr />
    <h3><a name="lua_tointegerx"><code>lua_tointegerx</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);</pre>

    <p />
    将 index 处的 Lua 值转换为一个有符号整数 <a href="#lua_Integer"><code>lua_Integer</code></a>。
    这个 Lua 值必须是整数 / 数字 / 可转换为整数的字符串(参见 <a href="#3.4.3">&sect;3.4.3</a>);
    否则，<code>lua_tointegerx</code> 返回 0。

    <p />
    如果 <code>isnum</code> 不为 <code>NULL</code>, 它的指向将被赋值为一个布尔值以表示操作是否成功。

    <hr />
    <h3><a name="lua_tolstring"><code>lua_tolstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>m</em>]</span>
    <pre>const char *lua_tolstring (lua_State *L, int index, size_t *len);</pre>

    <p />
    将 index 处的值转换为一个 C 字符串。
    如果 <code>len</code> 不为 <code>NULL</code>, 它将设置 <code>*len</code> 为字符串长度。
    这个 Lua 值必须是字符串或数字；
    否则，函数返回 <code>NULL</code>。
    如果这个值是一个数字，
    那么 <code>lua_tolstring</code> 会<em>将栈中的那个值转换为一个字符串</em>

    (这个改变使得在表遍历过程中将 <code>lua_tolstring</code> 用于键会使 <a href="#lua_next"><code>lua_next</code></a> 产生令人困惑的结果。)

    <p />
    <code>lua_tolstring</code> 返回 Lua 状态机中的字符串指针 (参见 <a href="#4.1.3">&sect;4.1.3</a>).
    这个字符串总是在最后一个字符后有一个 0('<code>\0</code>')(就像 C 中那样)，但是字符串中不会包含其它 0。

    <hr />
    <h3><a name="lua_tonumber"><code>lua_tonumber</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Number lua_tonumber (lua_State *L, int index);</pre>

    <p />
    等价于 <code>isnum</code> 为 <code>NULL</code> 的 <a href="#lua_tonumberx"><code>lua_tonumberx</code></a>。

    <hr />
    <h3><a name="lua_tonumberx"><code>lua_tonumberx</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);</pre>

    <p />
    将 index 处的 Lua 值转换为 C 类型 <a href="#lua_Number"><code>lua_Number</code></a> (参见 <a
        href="#lua_Number"><code>lua_Number</code></a>)。
    这个 Lua 值必须是一个数字或可以转换为数字的字符串(参见 <a href="#3.4.3">&sect;3.4.3</a>)；
    否则 <a href="#lua_tonumberx"><code>lua_tonumberx</code></a> 返回 0。

    <p />
    如果 <code>isnum</code> 不为 <code>NULL</code>, 它的指向将被赋值为一个布尔值以表示操作是否成功。

    <hr />
    <h3><a name="lua_topointer"><code>lua_topointer</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>const void *lua_topointer (lua_State *L, int index);</pre>

    <p />
    将 index 处的值转换为一个普通的 C 指针(<code>void*</code>)。
    这个值可以是一个用户数据/表/线程/字符串/函数；
    否则，<a href="#lua_topointer"><code>lua_topointer</code></a> 返回 <code>NULL</code>。
    不同的对象将会给出不同的指针。
    指针没有办法转换回原始值。

    <p />
    通常，此函数仅用于 hash 和调试信息。

    <hr />
    <h3><a name="lua_tostring"><code>lua_tostring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>m</em>]</span>
    <pre>const char *lua_tostring (lua_State *L, int index);</pre>

    <p />
    等价于 <code>len</code> 为 <code>NULL</code> 的 <a href="#lua_tolstring"><code>lua_tolstring</code></a>。

    <hr />
    <h3><a name="lua_tothread"><code>lua_tothread</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_State *lua_tothread (lua_State *L, int index);</pre>

    <p />
    将 index 处的值转换为一个 Lua 线程(表示为 <code>lua_State*</code>)。
    这个值必须是一个线程，否则，函数返回 <code>NULL</code>。

    <hr />
    <h3><a name="lua_touserdata"><code>lua_touserdata</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void *lua_touserdata (lua_State *L, int index);</pre>

    <p />
    如果 index 处的值是一个完全用户数据，返回它的内存块地址。
    如果该值是一个轻量用户数据，返回它的值(一个指针)。
    否则返回 <code>NULL</code>。

    <hr />
    <h3><a name="lua_type"><code>lua_type</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_type (lua_State *L, int index);</pre>

    <p />
    返回给定有效索引处的值的类型，或者当索引无效但是一个可接受索引时返回 <code>LUA_TNONE</code>。
    <a href="#lua_type"><code>lua_type</code></a> 返回的类型是下列定义在 <code>lua.h</code> 中的常量之一：
    <a name="pdf-LUA_TNIL"><code>LUA_TNIL</code></a>,
    <a name="pdf-LUA_TNUMBER"><code>LUA_TNUMBER</code></a>,
    <a name="pdf-LUA_TBOOLEAN"><code>LUA_TBOOLEAN</code></a>,
    <a name="pdf-LUA_TSTRING"><code>LUA_TSTRING</code></a>,
    <a name="pdf-LUA_TTABLE"><code>LUA_TTABLE</code></a>,
    <a name="pdf-LUA_TFUNCTION"><code>LUA_TFUNCTION</code></a>,
    <a name="pdf-LUA_TUSERDATA"><code>LUA_TUSERDATA</code></a>,
    <a name="pdf-LUA_TTHREAD"><code>LUA_TTHREAD</code></a>,
    <a name="pdf-LUA_TLIGHTUSERDATA"><code>LUA_TLIGHTUSERDATA</code></a>。

    <hr />
    <h3><a name="lua_typename"><code>lua_typename</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>const char *lua_typename (lua_State *L, int tp);</pre>

    <p />
    返回 <code>tp</code>(必须是 <a href="#lua_type"><code>lua_type</code></a> 的返回值之一) 对应类型的字符串表示，

    <hr />
    <h3><a name="lua_Unsigned"><code>lua_Unsigned</code></a></h3>
    <pre>typedef ... lua_Unsigned;</pre>

    <p />
    <a href="#lua_Integer"><code>lua_Integer</code></a> 的无符号版本。

    <hr />
    <h3><a name="lua_upvalueindex"><code>lua_upvalueindex</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_upvalueindex (int i);</pre>

    <p />
    返回表示当前运行函数的第 <code>i</code> 个上值伪索引(参见 <a href="#4.2">&sect;4.2</a>)。
    <code>i</code> 必须在 <em>[1,256]</em> 范围内.

    <hr />
    <h3><a name="lua_version"><code>lua_version</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Number lua_version (lua_State *L);</pre>

    <p />
    返回内核的版本号。

    <hr />
    <h3><a name="lua_WarnFunction"><code>lua_WarnFunction</code></a></h3>
    <pre>typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);</pre>

    <p />
    警告函数的类型，用于 Lua 发出警告。
    第一个参数是 <a href="#lua_setwarnf"><code>lua_setwarnf</code></a> 设置的一个不透明指针。
    第二个参数是警告消息。
    第三个参数是布尔值，它表示是否要在下一次调用中继续该消息。

    <p />
    查看 <a href="#pdf-warn"><code>warn</code></a> 以了解关于警告的更多细节。

    <hr />
    <h3><a name="lua_warning"><code>lua_warning</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_warning (lua_State *L, const char *msg, int tocont);</pre>

    <p />
    通过给定消息触发警告。调用 <code>tocont</code> 为真的消息应该在对该函数的另一个调用中继续。

    <p />
    查看 <a href="#pdf-warn"><code>warn</code></a> 以了解关于警告的更多细节。

    <hr />
    <h3><a name="lua_Writer"><code>lua_Writer</code></a></h3>
    <pre>typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);</pre>

    <p />
    用于 <a href="#lua_dump"><code>lua_dump</code></a> 的写入器函数类型。
    每当 <a href="#lua_dump"><code>lua_dump</code></a> 生成代码的另一部分时，它都会来调用这个写入器，
    并传入要写入的缓冲区(<code>p</code>)和它的尺寸(<code>sz</code>)以及传入给 <a href="#lua_dump"><code>lua_dump</code></a> 的 <code>ud</code> 参数。

    <p />
    写入器返回一个错误码：
    0 表示没有错误，任何其它值表示一个错误并且停止 <a href="#lua_dump"><code>lua_dump</code></a> 再次调用写入器。

    <hr />
    <h3><a name="lua_xmove"><code>lua_xmove</code></a></h3>
    <p />
    <span class="apii">[-?, +?, &ndash;]</span>
    <pre>void lua_xmove (lua_State *from, lua_State *to, int n);</pre>

    <p />
    交换同一状态机中的两个不同线程的值。

    <p />
    函数从 <code>from</code> 栈中弹出 <code>n</code> 个值，并且将它们压入 <code>to</code> 栈。

    <hr />
    <h3><a name="lua_yield"><code>lua_yield</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>v</em>]</span>
    <pre>int lua_yield (lua_State *L, int nresults);</pre>

    <p />
    这个函数等价于 <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
    但是它不提供延续函数 (参见 <a href="#4.5">&sect;4.5</a>)。
    因此，当延续线程时，它会继续运行调用 <code>lua_yield</code> 函数的函数。
    为了避免意外，函数应该只在尾调用中调用。

    <hr />
    <h3><a name="lua_yieldk"><code>lua_yieldk</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>v</em>]</span>
    <pre>int lua_yieldk (lua_State *L,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);</pre>

    <p />
    让出协程(线程)。

    <p />
    当一个 C 函数调用 <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
    运行的协程暂停执行，并且启动这个协程的 <a href="#lua_resume"><code>lua_resume</code></a> 函数调用返回。
    参数 <code>nresults</code> 指栈上需返回给 <a href="#lua_resume"><code>lua_resume</code></a> 的返回值的个数。

    <p />
    当协程再次延续，Lua 调用指定的延续函数 <code>k</code> 以延续让出的 C 函数的执行(参见 <a href="#4.5">&sect;4.5</a>)。
    延续函数接收和之前函数一样的栈，移除 <code>n</code> 个结果值并且替换为要传入给 <a href="#lua_resume"><code>lua_resume</code></a> 的参数。
    此外，延续函数还会接收传给 <a href="#lua_yieldk"><code>lua_yieldk</code></a> 的 <code>ctx</code>

    <p />
    通常，函数不会返回；
    当协程一次次延续，将从延续函数继续运行。
    然后，有一种特殊情况，即从行或计数钩子内部调用该函数(参见 <a href="#4.7">&sect;4.7</a>)。
    这种情况, <code>lua_yieldk</code> 不可提供延续函数
    (也就是类似 <a href="#lua_yield"><code>lua_yield</code></a> 的形式)也没有结果值，并且钩子应该在调用后立即返回。
    一旦协程再次被延续，Lua 会使协程让出，并继续运行触发钩子的 Lua 函数。

    <p />
    在一个没有延续函数的 C 调用线程(所谓的 <em>C-call 边界</em>)或在一个不在 resume 中运行的线程(通常是主线程)中调用此函数会抛出一个错误。

    <h2>4.7 &ndash; <a name="4.7">调试接口</a></h2>

    <p />
    Lua 没有内置的调试工具。
    取而代之的是，它通过函数和 <em>钩子</em> 提供了一组特殊接口。
    这组接口允许构造不同类型的调试器、分析器和其它需要从解释器获取”内部信息“的工具。

    <hr />
    <h3><a name="lua_Debug"><code>lua_Debug</code></a></h3>
    <pre>typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  size_t srclen;              /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) number of upvalues */
  unsigned char nparams;      /* (u) number of parameters */
  char isvararg;              /* (u) */
  char istailcall;            /* (t) */
  unsigned short ftransfer;   /* (r) - */
  unsigned short ntransfer;   /* (r) number of transferred values */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* private part */
  <em>other fields</em>
} lua_Debug;</pre>

    <p />
    一个携带有有关函数或活动记录的各种信息的结构。
    <a href="#lua_getstack"><code>lua_getstack</code></a> 只会填充结构的私有部分供后面使用。
    要填充 <a href="#lua_Debug"><code>lua_Debug</code></a> 其它字段，你必须使用相应参数调用 <a
        href="#lua_getinfo"><code>lua_getinfo</code></a>
    (具体来说，要获取一个字段，你必须将字段注释中的字母作为 <a href="#lua_getinfo"><code>lua_getinfo</code></a> 的参数 <code>what</code>)

    <p />
    <a href="#lua_Debug"><code>lua_Debug</code></a> 的字段含义:

    <ul>
        <li><b><code>source</code>: </b>
            创建该函数的代码块来源。
            如果 <code>source</code> 以 '<code>@</code>' 开头，意味着这个函数定义在一个文件中，文件名紧随 '<code>@</code>' 之后。
            如果 <code>source</code> 以 '<code>=</code>' 开头，其剩余内容以用户依赖的方式描述了源代码。
            否则，函数是通过一个字符串定义的，<code>source</code> 就是该字符串。
        </li>

        <li><b><code>srclen</code>: </b>
            字符串 <code>source</code> 的长度。
        </li>

        <li><b><code>short_src</code>: </b>
            <code>source</code> 的"可打印版本", 用于错误消息。
        </li>

        <li><b><code>linedefined</code>: </b>
            函数定义的起始行号。
        </li>

        <li><b><code>lastlinedefined</code>: </b>
            函数定义的结尾行号。
        </li>

        <li><b><code>what</code>: </b>
            如果函数是一个 Lua 函数则为 <code>"Lua"</code>，
            如果是一个 C 函数则为 <code>"C"</code>，
            如果是代码块的主要部分则为 <code>"main"</code>。
        </li>

        <li><b><code>currentline</code>: </b>
            给定函数当前执行的行号。
            当没有可用行信息时 <code>currentline</code> 被设置为 -1。
        </li>

        <li><b><code>name</code>: </b>
            给定函数的合理名字。
            因为 Lua 中函数是第一类值，它们没有固定名字：
            一些函数能够作为多个全局变量的值，而另一些只能存储在表字段中。
            <code>lua_getinfo</code> 函数检测函数的调用方式以找到一个合适的名字。
            如果没有找到名字，<code>name</code> 被设置为 <code>NULL</code>。
        </li>

        <li><b><code>namewhat</code>: </b>
            解释 <code>name</code> 字段。
            根据函数的调用方式， <code>namewhat</code> 的值可以是 <code>"global"</code>, <code>"local"</code>, <code>"method"</code>,
            <code>"field"</code>, <code>"upvalue"</code>, 或 <code>""</code> (空字符串),
            (Lua 在没有其它选项可用时使用空字符串)
        </li>

        <li><b><code>istailcall</code>: </b>
            如果函数是由尾调用调用则为 true，这种情况下，此层级的调用者不在栈中。
        </li>

        <li><b><code>nups</code>: </b>
            函数的上值个数
        </li>

        <li><b><code>nparams</code>: </b>
            函数的参数个数(对于 C 函数，总是为 0)。
        </li>

        <li><b><code>isvararg</code>: </b>
            如果函数是可变参数函数则为 true(对于 C 函数，总是为 true)。
        </li>

        <li><b><code>ftransfer</code>: </b>
            ”被转移的“(调用时的参数或返回时的返回值)的第一个值在栈中的索引(其它的值在连续的索引中)。
            使用这些索引，你可以通过 <a href="#lua_getlocal"><code>lua_getlocal</code></a> 和 <a
                href="#lua_setlocal"><code>lua_setlocal</code></a> 来访问或修改这些值。
            该字段仅在调用钩子期间有意义，表示第一个参数或在钩子返回时表示第一个返回值(对于调用钩子，此值始终为 1)。
        </li>

        <li><b><code>ntransfer</code>: </b>
            转移的值数量(参见上一项)。
            (对于 Lua 函数的调用，这个值总是等于 <code>nparams</code>)
        </li>
    </ul>

    <hr />
    <h3><a name="lua_gethook"><code>lua_gethook</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_Hook lua_gethook (lua_State *L);</pre>

    <p />
    返回当前的钩子函数。

    <hr />
    <h3><a name="lua_gethookcount"><code>lua_gethookcount</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_gethookcount (lua_State *L);</pre>

    <p />
    返回当前钩子计数。

    <hr />
    <h3><a name="lua_gethookmask"><code>lua_gethookmask</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_gethookmask (lua_State *L);</pre>

    <p />
    返回当前钩子掩码。

    <hr />
    <h3><a name="lua_getinfo"><code>lua_getinfo</code></a></h3>
    <p />
    <span class="apii">[-(0|1), +(0|1|2), <em>m</em>]</span>
    <pre>int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);</pre>

    <p />
    获取一个函数或函数运行的相关信息。

    <p />
    要获取函数调用相关信息，参数 <code>ar</code> 必须是一个有效的活动记录，
    这条活动记录必须是前一次调用 <a href="#lua_getstack"><code>lua_getstack</code></a> 得到的，
    或是作为钩子(参见 <a href="#lua_Hook"><code>lua_Hook</code></a>) 的参数。

    <p />
    要获取一个函数相关信息，需要把它压入栈，并且 <code>what</code> 字符串以 '<code>&gt;</code>' 开头(这会让 <code>lua_getinfo</code> 把函数从栈上弹出)。
    例如，要知道一个函数 <code>f</code> 定义在哪行，你应该写入下面代码：

    <pre>
     lua_Debug ar;
     lua_getglobal(L, "f");  /* get global 'f' */
     lua_getinfo(L, "&gt;S", &amp;ar);
     printf("%d\n", ar.linedefined);
</pre>

    <p />
    字符串 <code>what</code> 中的每个字符都筛选结构体 <code>ar</code> 中的一些字段被填充或一个值被压入栈。
    (这些字符也被记录在结构体 <a href="#lua_Debug"><code>lua_Debug</code></a> 的声明中，位于每个字段之后的注释中的圆括号中)

    <ul>
        <li><b>'<code>f</code>': </b>
            将运行在给定层级的函数压入栈；
        </li>

        <li><b>'<code>l</code>': </b> 填充字段 <code>currentline</code>;
        </li>

        <li><b>'<code>n</code>': </b> 填充字段 <code>name</code> 和 <code>namewhat</code>;
        </li>

        <li><b>'<code>r</code>': </b> 填充字段 <code>ftransfer</code> 和 <code>ntransfer</code>;
        </li>

        <li><b>'<code>S</code>': </b>
            填充字段 <code>source</code>, <code>short_src</code>,
            <code>linedefined</code>, <code>lastlinedefined</code> 和 <code>what</code>;
        </li>

        <li><b>'<code>t</code>': </b> 填充字段 <code>istailcall</code>;
        </li>

        <li><b>'<code>u</code>': </b> 填充字段
            <code>nups</code>, <code>nparams</code> 和 <code>isvararg</code>;
        </li>

        <li><b>'<code>L</code>': </b>
            将一个表压入栈，这个表是函数的行的一些关联代码，也就是说，你可以在这些行上放置断点；
            (没有代码的行包括空行和注释)
            如果选项包括 '<code>f</code>'，表将在函数之后压入。
            这是唯一一个可能会抛出内存错误的选项。
        </li>
    </ul>

    <p />
    函数返回 0 以表示 <code>what</code> 中包含无效选项；
    即便如此，有效的选项仍会正确处理。

    <hr />
    <h3><a name="lua_getlocal"><code>lua_getlocal</code></a></h3>
    <p />
    <span class="apii">[-0, +(0|1), &ndash;]</span>
    <pre>const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);</pre>

    <p />
    获取给定活动记录或函数的局部变量或临时值的有关信息。

    <p />
    第一种情况中，参数 <code>ar</code> 必须是有个有效的活动记录，
    记录由先前对 <a href="#lua_getstack"><code>lua_getstack</code></a> 的调用填充，
    或作为钩子的参数(参见<a href="#lua_Hook"><code>lua_Hook</code></a>)。
    索引 <code>n</code> 用于选择要检查的局部变量；
    有关变量索引和名称的详细信息，请参见 <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a>。

    <p />
    <a href="#lua_getlocal"><code>lua_getlocal</code></a> 将变量值压入栈并返回它的名字。

    <p />
    在第二种情况中， <code>ar</code> 必须为 <code>NULL</code> 并且要检查的函数必须在栈顶。
    在这种情况下，只有 Lua 函数的参数是可见的(因为没有变量的活跃信息)，并且不会将任何值推送到堆栈上。

    <p />
    当索引 <code>n</code> 大于活跃局部变量的个数时返回 <code>NULL</code> (并且不会压入任何东西)

    <hr />
    <h3><a name="lua_getstack"><code>lua_getstack</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>int lua_getstack (lua_State *L, int level, lua_Debug *ar);</pre>

    <p />
    获取解释器运行时栈相关信息。

    <p />
    函数通过一个给定层级执行的函数的 <em>活动记录</em> 的标识填充 <a href="#lua_Debug"><code>lua_Debug</code></a> 结构体的部分内容，
    层级 0 表示当前运行的函数，层级 <em>n+1</em> 表示调用层级 <em>n</em> 的函数。
    (尾调用除外，它不在栈中计数)
    当通过一个大于栈深度的层级调用 <a href="#lua_getstack"><code>lua_getstack</code></a> 时返回 0;
    否则返回 1。

    <hr />
    <h3><a name="lua_getupvalue"><code>lua_getupvalue</code></a></h3>
    <p />
    <span class="apii">[-0, +(0|1), &ndash;]</span>
    <pre>const char *lua_getupvalue (lua_State *L, int funcindex, int n);</pre>

    <p />
    获取在 <code>funcindex</code> 索引处的闭包的第 <code>n</code> 个上值的信息。
    函数将上值的值压入栈并返回它的名字。
    当索引 <code>n</code> 大于上值的个数时返回 <code>NULL</code> (并且不会压入任何东西)

    <p />
    参见 <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> 以了解关于上值的更多信息。

    <hr />
    <h3><a name="lua_Hook"><code>lua_Hook</code></a></h3>
    <pre>typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);</pre>

    <p />
    调试钩子函数的类型。

    <p />
    当钩子被调用时， <code>ar</code> 参数的 <code>event</code> 字段会被设置为触发钩子的特定事件。
    Lua 使用以下常量定义这些事件:
    <a name="pdf-LUA_HOOKCALL"><code>LUA_HOOKCALL</code></a>, <a name="pdf-LUA_HOOKRET"><code>LUA_HOOKRET</code></a>,
    <a name="pdf-LUA_HOOKTAILCALL"><code>LUA_HOOKTAILCALL</code></a>, <a
        name="pdf-LUA_HOOKLINE"><code>LUA_HOOKLINE</code></a>, <a name="pdf-LUA_HOOKCOUNT"><code>LUA_HOOKCOUNT</code></a>。
    此外，对于行事件，字段 <code>currentline</code> 也会被设置。
    要获取 <code>ar</code> 中的其它字段，钩子必须调用 <a href="#lua_getinfo"><code>lua_getinfo</code></a>。

    <p />
    对于调用事件，<code>event</code> 可以为普通调用 <code>LUA_HOOKCALL</code> 或尾调用 <code>LUA_HOOKTAILCALL</code>;
    在尾调用的情况下，不会有相应的返回事件。

    <p />
    当 Lua 运行一个钩子时，它会使其它钩子失效。
    因此，如果一个钩子回调 Lua 以执行一个函数或代码块，这个执行不会调用其它钩子。

    <p />
    钩子函数不可以延续，即不能用一个非空的 <code>k</code> 调用 </code> <a href="#lua_yieldk"><code>lua_yieldk</code></a>,
    <a href="#lua_pcallk"><code>lua_pcallk</code></a> 或 <a href="#lua_callk"><code>lua_callk</code></a>。

    <p />
    钩子函数可以在满足以下条件时让出：只有计数和行事件可以让出；
    要让出，一个钩子函数必须通过为 0 的 <code>nresults</code> (也就是，没有返回值) 调用 <a href="#lua_yield"><code>lua_yield</code></a> 以结束它的执行。

    <hr />
    <h3><a name="lua_sethook"><code>lua_sethook</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);</pre>

    <p />
    设置调试钩子函数。

    <p />
    参数 <code>f</code> 为钩子函数。
    <code>mask</code> 指定钩子函数的事件：
    它由下面常量位进行按位或组成
    <a name="pdf-LUA_MASKCALL"><code>LUA_MASKCALL</code></a>,
    <a name="pdf-LUA_MASKRET"><code>LUA_MASKRET</code></a>,
    <a name="pdf-LUA_MASKLINE"><code>LUA_MASKLINE</code></a>
    和 <a name="pdf-LUA_MASKCOUNT"><code>LUA_MASKCOUNT</code></a>。
    <code>count</code> 参数值在 <code>mask</code> 包含 <code>LUA_MASKCOUNT</code> 时有意义。

    每个事件的钩子调用解释如下：

    <ul>
        <li><b>call hook(调用钩子): </b> 在解释器调用一个函数时调用。钩子在 Lua 进入新函数后调用。</li>
        <li><b>return hook(返回钩子): </b> 在解释器从一个函数返回时调用。钩子在 Lua 离开函数前调用。</li>
        <li><b>line hook(行钩子): </b> 在解释器即将开始一行新代码执行时，或跳回到代码时(即使是同一行)时调用。事件只发生在 Lua 在执行一个 Lua函数时。</li>
        <li><b>count hook(计数钩子): </b> 在解释器执行每一次 <code>count</code> 指令后调用。事件只发生在 Lua 在执行一个 Lua函数时。</li>
    </ul>

    <p />
    钩子可以通过设置 <code>mask</code> 为 0 以关闭。

    <hr />
    <h3><a name="lua_setlocal"><code>lua_setlocal</code></a></h3>
    <p />
    <span class="apii">[-(0|1), +0, &ndash;]</span>
    <pre>const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);</pre>

    <p />
    设置给定活动记录的局部变量的值。
    将该变量的值赋值为栈顶的值并返回它的名字。
    也将该值从栈中弹出。

    <p />
    当索引大于活动的局部变量数时返回 <code>NULL</code>(并且不弹出任何东西)。

    <p />
    参数 <code>ar</code> 和 <code>n</code> 与函数 <a href="#lua_getlocal"><code>lua_getlocal</code></a> 中的一样。

    <hr />
    <h3><a name="lua_setupvalue"><code>lua_setupvalue</code></a></h3>
    <p />
    <span class="apii">[-(0|1), +0, &ndash;]</span>
    <pre>const char *lua_setupvalue (lua_State *L, int funcindex, int n);</pre>

    <p />
    设置闭包的上值的值。
    将该上值的值赋值为栈顶的值并返回它的名字。
    也将该值从栈中弹出。

    <p />
    当索引大于活动的上值数时返回 <code>NULL</code>(并且不弹出任何东西)。

    <p />
    参数 <code>funcindex</code> 和 <code>n</code> 与函数 <a href="#lua_getupvalue"><code>lua_getupvalue</code></a> 中的一样。

    <hr />
    <h3><a name="lua_upvalueid"><code>lua_upvalueid</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void *lua_upvalueid (lua_State *L, int funcindex, int n);</pre>

    <p />
    从索引 <code>funcindex</code> 处的闭包返回编号 <code>n</code> 的上值的 id(唯一标识符)。

    <p />
    这些 id 允许程序检测不同的闭包是否共享上值。
    共享一个上值的Lua闭包 (即访问同一个外部局部变量) 将为那些上值索引返回相同的 id。

    <p />
    参数 <code>funcindex</code> 和 <code>n</code> 与函数 <a href="#lua_getupvalue"><code>lua_getupvalue</code></a> 中的一样,
    但是 <code>n</code> 不能大于上值的数量。

    <hr />
    <h3><a name="lua_upvaluejoin"><code>lua_upvaluejoin</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);</pre>

    <p />
    使索引 <code>funcindex1</code> 处的闭包的第 <code>n1</code> 个上值指向索引 <code>funcindex2</code> 的闭包的第 <code>n2</code> 个上值。

    <h1>5 &ndash; <a name="5">辅助库</a></h1>

    <p />
    <em>辅助库</em> 提供一些便捷的函数以连接 C 和 Lua。
    基础 API 提供了 C 和 Lua 中的所有交互的基础函数，
    辅助库为一些常见的任务提供了更高级的函数。

    <p />
    辅助库中的所有函数和类型都在头文件 <code>lauxlib.h</code> 中定义，并且都以 <code>luaL_</code> 为前缀。

    <p />
    辅助库中的所有函数都建立在基础 API 上，它们提供的功能都可以用该API完成。
    不过，使用辅助库使代码更具一致性。

    <p />
    辅助库中的部分函数在内部使用了一些额外栈槽。
    当辅助库中的函数使用的槽少于5个，它不会检查栈大小；它只是假定有足够的插槽。

    <p />
    辅助库中的部分函数用以检测 C 函数参数。
    因为错误消息为参数提设置了格式(例如,"<code>bad argument #1</code>")，
    您不应该将这些函数用于其它堆栈值。

    <p />
    名为 <code>luaL_check*</code> 的函数总是在检测不成立时时抛出错误。

    <h2>5.1 &ndash; <a name="5.1">函数和类型</a></h2>

    <p />
    这里我们按字母顺序列出辅助库中的所有函数和类型。

    <hr />
    <h3><a name="luaL_addchar"><code>luaL_addchar</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>void luaL_addchar (luaL_Buffer *B, char c);</pre>

    <p />
    添加一个字节 <code>c</code> 到缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中。

    <hr />
    <h3><a name="luaL_addgsub"><code>luaL_addgsub</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>const void luaL_addgsub (luaL_Buffer *B, const char *s,
                         const char *p, const char *r);</pre>

    <p />
    添加字符串 <code>s</code> 的副本至缓冲 <code>B</code>(参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中,
    将所有出现的字符串 <code>p</code> 替换为字符串 <code>r</code>。

    <hr />
    <h3><a name="luaL_addlstring"><code>luaL_addlstring</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);</pre>

    <p />
    将 <code>s</code> 指向的长度 <code>l</code> 的字符串添加到缓冲 <code>B</code> (参见 <a
        href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中
    字符串可以包含嵌入 0。

    <hr />
    <h3><a name="luaL_addsize"><code>luaL_addsize</code></a></h3>
    <p />
    <span class="apii">[-?, +?, &ndash;]</span>
    <pre>void luaL_addsize (luaL_Buffer *B, size_t n);</pre>

    <p />
    将之前已经复制到缓冲区 (参见 <a href="#luaL_prepbuffer"><code>luaL_prepbuffer</code></a>) 的长度为 <code>n</code> 的字符串添加到缓冲 <code>B</code> 中。

    <hr />
    <h3><a name="luaL_addstring"><code>luaL_addstring</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>void luaL_addstring (luaL_Buffer *B, const char *s);</pre>

    <p />
    将 <code>s</code> 指向的零结尾字符串添加到缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中。

    <hr />
    <h3><a name="luaL_addvalue"><code>luaL_addvalue</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>void luaL_addvalue (luaL_Buffer *B);</pre>

    <p />
    将栈顶的值添加到缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中。
    弹出该值。

    <p />
    这是唯一要(且必须)使用栈上额外元素调用的字符串缓冲函数，该元素是要添加的缓冲区的值。

    <hr />
    <h3><a name="luaL_argcheck"><code>luaL_argcheck</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_argcheck (lua_State *L,
                    int cond,
                    int arg,
                    const char *extramsg);</pre>

    <p />
    检测 <code>cond</code> 是否为 true。
    如果不是，则使用标准信息 (参见 <a href="#luaL_argerror"><code>luaL_argerror</code></a>) 抛出一个错误。

    <hr />
    <h3><a name="luaL_argerror"><code>luaL_argerror</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>int luaL_argerror (lua_State *L, int arg, const char *extramsg);</pre>

    <p />
    抛出一个报告调用 C 函数的参数 <code>arg</code> 的错误，使用包含 <code>extramsg</code> 作为注释的标准消息：

    <pre>
     bad argument #<em>arg</em> to '<em>funcname</em>' (<em>extramsg</em>)
</pre>
    <p />
    函数永远不会返回。

    <hr />
    <h3><a name="luaL_argexpected"><code>luaL_argexpected</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_argexpected (lua_State *L,
                       int cond,
                       int arg,
                       const char *tname);</pre>

    <p />
    检测 <code>cond</code> 是否为 true。
    如果不是，则使用标准信息 (参见 <a href="#luaL_argerror"><code>luaL_argerror</code></a>) 抛出一个错误。
    如果不是，使用关于参数 <code>arg</code> 的类型错误作为标准信息 (参见 <a href="#luaL_typeerror"><code>luaL_typeerror</code></a>) 抛出一个错误。

    <hr />
    <h3><a name="luaL_Buffer"><code>luaL_Buffer</code></a></h3>
    <pre>typedef struct luaL_Buffer luaL_Buffer;</pre>

    <p />
    <em>字符串缓冲</em> 类型.

    <p />
    一个字符串缓冲允许 C 代码构建 Lua 字符串片段。
    它的使用模式如下：

    <ul>
        <li>首先声明类型 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a> 的变量 <code>b</code>。
        </li>

        <li>调用 <code>luaL_buffinit(L, &amp;b)</code> 来初始化它。</li>

        <li>
            然后调用任意 <code>luaL_add*</code> 函数将添加字符串片段到缓冲中。
        </li>

        <li>
            最后，调用 <code>luaL_pushresult(&amp;b)</code>。
            这个调用将把最终的字符串放在栈顶。
        </li>

    </ul>

    <p />
    如果你事先知道结果字符串的最大大小，你可以这样使用该缓冲：

    <ul>
        <li>首先声明类型 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a> 的变量 <code>b</code>。
        </li>

        <li>然后调用 <code>luaL_buffinitsize(L, &amp;b, sz)</code> 来初始化并预分配 <code>sz</code> 大小的空间。
        </li>

        <li>然后生成字符串到该空间中。</li>

        <li>
            最后调用 <code>luaL_pushresultsize(&amp;b, sz)</code>, <code>sz</code> 是复制到该空间的结果字符串的总大小
            (它可能小于或等于预分配大小)。
        </li>
    </ul>

    <p />
    正常操作过程中, 字符串缓冲使用不定量的栈槽。
    因此，使用字符串缓冲时，你不能假定你知道栈顶的位置。
    你可以在连续的缓冲操作调用之间使用栈，只要该使用是平衡的；
    也就是说，当你调用缓冲操作时，栈是相同层级，它紧跟在前面的缓冲操作之后
    (唯一的例外是 <a href="#luaL_addvalue"><code>luaL_addvalue</code></a>)。
    调用 <a href="#luaL_pushresult"><code>luaL_pushresult</code></a> 之后, 栈返回到缓冲初始化之前的层级，并在顶部压入最终字符串。

    <hr />
    <h3><a name="luaL_buffaddr"><code>luaL_buffaddr</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>char *luaL_buffaddr (luaL_Buffer *B);</pre>

    <p />
    返回缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 当前内容的地址。
    注意，对缓冲的所有添加操作都可能使该地址无效。

    <hr />
    <h3><a name="luaL_buffinit"><code>luaL_buffinit</code></a></h3>
    <p />
    <span class="apii">[-0, +?, &ndash;]</span>
    <pre>void luaL_buffinit (lua_State *L, luaL_Buffer *B);</pre>

    <p />
    初始化缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>)。
    函数不分配任何空间；缓冲必须被声明为一个变量。

    <hr />
    <h3><a name="luaL_bufflen"><code>luaL_bufflen</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>size_t luaL_bufflen (luaL_Buffer *B);</pre>

    <p />
    返回缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中当前内容的长度。

    <hr />
    <h3><a name="luaL_buffinitsize"><code>luaL_buffinitsize</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);</pre>

    <p />
    等价于顺序调用 <a href="#luaL_buffinit"><code>luaL_buffinit</code></a>, <a
        href="#luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a>。

    <hr />
    <h3><a name="luaL_buffsub"><code>luaL_buffsub</code></a></h3>
    <p />
    <span class="apii">[-?, +?, &ndash;]</span>
    <pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>

    <p />
    从缓冲 <code>B</code> (参见 <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 中移除 <code>n</code> 字节。
    缓冲中需要至少有这么多字节。

    <hr />
    <h3><a name="luaL_callmeta"><code>luaL_callmeta</code></a></h3>
    <p />
    <span class="apii">[-0, +(0|1), <em>e</em>]</span>
    <pre>int luaL_callmeta (lua_State *L, int obj, const char *e);</pre>

    <p />
    调用元方法。

    <p />
    如果索引 <code>obj</code> 的对象有元表并且这个元表有字段 <code>e</code>, 函数将该对象作为其唯一参数调用这个字段。
    这种情况函数返回 true 并且将调用的返回值压入栈。
    如果没有元表或元方法，函数返回 false 并且不会压入任何值。

    <hr />
    <h3><a name="luaL_checkany"><code>luaL_checkany</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_checkany (lua_State *L, int arg);</pre>

    <p />
    检测是否在 <code>arg</code> 位置有一个任意类型(包括 <b>nil</b>)的参数。

    <hr />
    <h3><a name="luaL_checkinteger"><code>luaL_checkinteger</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>lua_Integer luaL_checkinteger (lua_State *L, int arg);</pre>

    <p />
    检测函数参数 <code>arg</code> 是否为一个整数(或能被转换为整数)并且返回这个整数。

    <hr />
    <h3><a name="luaL_checklstring"><code>luaL_checklstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>const char *luaL_checklstring (lua_State *L, int arg, size_t *l);</pre>

    <p />
    检测函数参数 <code>arg</code> 是否是一个字符串并返回这个字符串。
    如果 <code>l</code> 不为 <code>NULL</code> 使用字符串的长度填充其引用。

    <p />
    函数使用 <a href="#lua_tolstring"><code>lua_tolstring</code></a> 以获取结果，因此其所有转换和注意事项都适用于它。

    <hr />
    <h3><a name="luaL_checknumber"><code>luaL_checknumber</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>lua_Number luaL_checknumber (lua_State *L, int arg);</pre>

    <p />
    检测函数参数 <code>arg</code> 是否为一个数字并将其作为一个 <code>lua_Number</code> 返回。

    <hr />
    <h3><a name="luaL_checkoption"><code>luaL_checkoption</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>int luaL_checkoption (lua_State *L,
                      int arg,
                      const char *def,
                      const char *const lst[]);</pre>

    <p />
    检测函数第 <code>arg</code> 参数是否为一个字符串并且在数组 <code>lst</code> (必须以 <code>NULL</code> 结尾) 中搜索该字符串。
    返回字符串在数组中的索引。如果参数不是一个字符串或不能找到字符串则抛出错误。

    <p />
    如果 <code>def</code> 不为 <code>NULL</code>, 当没有参数 <code>arg</code> 或参数为 <b>nil</b> 时函数使用 <code>def</code> 作为默认值。

    <p />
    这是一个将字符串转换为 C 枚举非常有用的函数。(Lua 库中通常使用字符串而不是数字来选择选项。)

    <hr />
    <h3><a name="luaL_checkstack"><code>luaL_checkstack</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_checkstack (lua_State *L, int sz, const char *msg);</pre>

    <p />
    将栈大小扩展到 <code>top + sz</code> 个元素, 如果栈不能扩展到该大小则抛出错误。
    <code>msg</code> 是放入错误消息中的额外的文本 (为 <code>NULL</code> 则没有为信息).

    <hr />
    <h3><a name="luaL_checkstring"><code>luaL_checkstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>const char *luaL_checkstring (lua_State *L, int arg);</pre>

    <p />
    检测函数参数 <code>arg</code> 是否是一个字符串并返回这个字符串。

    <p />
    函数使用 <a href="#lua_tolstring"><code>lua_tolstring</code></a> 以获取结果，
    因此所有转换和注意事项都适用于它。

    <hr />
    <h3><a name="luaL_checktype"><code>luaL_checktype</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_checktype (lua_State *L, int arg, int t);</pre>

    <p />
    检测函数第 <code>arg</code> 个参数类型为 <code>t</code>。
    <a href="#lua_type"><code>lua_type</code></a> 用于 <code>t</code> 的类型编码。

    <hr />
    <h3><a name="luaL_checkudata"><code>luaL_checkudata</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void *luaL_checkudata (lua_State *L, int arg, const char *tname);</pre>

    <p />
    检测函数第 <code>arg</code> 个参数是否是一个类型为 <code>tname</code>(参见 <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>) 的用户数据并且返回用户数据的内存块地址(参见 <a href="#lua_touserdata"><code>lua_touserdata</code></a>)。

    <hr />
    <h3><a name="luaL_checkversion"><code>luaL_checkversion</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>void luaL_checkversion (lua_State *L);</pre>

    <p />
    检测调用的代码和被调用的库是否使用相同的 Lua 版本和数字类型。

    <hr />
    <h3><a name="luaL_dofile"><code>luaL_dofile</code></a></h3>
    <p />
    <span class="apii">[-0, +?, <em>m</em>]</span>
    <pre>int luaL_dofile (lua_State *L, const char *filename);</pre>

    <p />
    加载并运行给定文件。
    它被定义为下面宏：

    <pre>
     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre>
    <p />
    没有错误则返回 0(<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) ， 否则返回 1。

    <hr />
    <h3><a name="luaL_dostring"><code>luaL_dostring</code></a></h3>
    <p />
    <span class="apii">[-0, +?, &ndash;]</span>
    <pre>int luaL_dostring (lua_State *L, const char *str);</pre>

    <p />
    加载并运行给定字符串。
    它被定义为下面宏：

    <pre>
     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre>
    <p />
    没有错误则返回 0(<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) ， 否则返回 1。

    <hr />
    <h3><a name="luaL_error"><code>luaL_error</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>int luaL_error (lua_State *L, const char *fmt, ...);</pre>

    <p />
    抛出错误。
    错误消息的格式由 <code>fmt</code> 加上所有额外参数决定， 遵循和 <a href="#lua_pushfstring"><code>lua_pushfstring</code></a> 一致的规则。
    它还在消息的开头添加文件名和发生错误的行号，如果这些信息可用的话。

    <p />
    函数不会返回，但是在 C 函数中使用它的习惯做法是 <code>return luaL_error(<em>args</em>)</code>。

    <hr />
    <h3><a name="luaL_execresult"><code>luaL_execresult</code></a></h3>
    <p />
    <span class="apii">[-0, +3, <em>m</em>]</span>
    <pre>int luaL_execresult (lua_State *L, int stat);</pre>

    <p />
    函数为标准库中的进程相关函数生成返回值 (<a href="#pdf-os.execute"><code>os.execute</code></a> 和 <a
        href="#pdf-io.close"><code>io.close</code></a>)。

    <hr />
    <h3><a name="luaL_fileresult"><code>luaL_fileresult</code></a></h3>
    <p />
    <span class="apii">[-0, +(1|3), <em>m</em>]</span>
    <pre>int luaL_fileresult (lua_State *L, int stat, const char *fname);</pre>

    <p />
    函数为标准库中的文件相关函数生成返回值
    (<a href="#pdf-io.open"><code>io.open</code></a>, <a href="#pdf-os.rename"><code>os.rename</code></a>, <a
        href="#pdf-file:seek"><code>file:seek</code></a>, 等等)。

    <hr />
    <h3><a name="luaL_getmetafield"><code>luaL_getmetafield</code></a></h3>
    <p />
    <span class="apii">[-0, +(0|1), <em>m</em>]</span>
    <pre>int luaL_getmetafield (lua_State *L, int obj, const char *e);</pre>

    <p />
    将索引 <code>obj</code> 处的对象的元表的 <code>e</code> 压入栈并返回压入值的类型。
    如果对象没有元表，或没有这个字段，什么都不压入并返回 <code>LUA_TNIL</code>。

    <hr />
    <h3><a name="luaL_getmetatable"><code>luaL_getmetatable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>int luaL_getmetatable (lua_State *L, const char *tname);</pre>

    <p />
    将与注册表中的 <code>tname</code> 相关联的元表(如果没有元表与该名字相关联则为 <b>nil</b>)压入栈 (参见 <a
        href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>),
    返回压入值的类型。

    <hr />
    <h3><a name="luaL_getsubtable"><code>luaL_getsubtable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>int luaL_getsubtable (lua_State *L, int idx, const char *fname);</pre>

    <p />
    确保值 <code>t[fname]</code>(<code>t</code> 为索引 <code>idx</code> 处的值) 是一个表并将该表压入栈。
    如果在前面的表中找到了则返回 true， 如果创建一个新表则返回 false。

    <hr />
    <h3><a name="luaL_gsub"><code>luaL_gsub</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);</pre>

    <p />
    创建一个字符串 <code>s</code> 的副本, 使用字符串 <code>r</code> 替换所有的出现的字符串 <code>p</code>。
    将结果字符串压入栈并返回它。

    <hr />
    <h3><a name="luaL_len"><code>luaL_len</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>e</em>]</span>
    <pre>lua_Integer luaL_len (lua_State *L, int index);</pre>

    <p />
    以数字形式返回 index 处值的"长度"。
    它等价于 Lua 中的 '<code>#</code>' 操作符 (参见 <a href="#3.4.7">&sect;3.4.7</a>)。
    如果操作结果不是一个整数则抛出错误(这种情况只发生在元方法中)。

    <hr />
    <h3><a name="luaL_loadbuffer"><code>luaL_loadbuffer</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);</pre>

    <p />
    等价于 <code>mode</code> 为 <code>NULL</code> 的 <a href="#luaL_loadbufferx"><code>luaL_loadbufferx</code></a>。

    <hr />
    <h3><a name="luaL_loadbufferx"><code>luaL_loadbufferx</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int luaL_loadbufferx (lua_State *L,
                      const char *buff,
                      size_t sz,
                      const char *name,
                      const char *mode);</pre>

    <p />
    将缓冲加载为 Lua 代码块。
    这个函数使用 <a href="#lua_load"><code>lua_load</code></a> 来加载 <code>buff</code> 所指向的缓冲区中大小为 <code>sz</code> 的代码块。

    <p />
    函数返回结果和 <a href="#lua_load"><code>lua_load</code></a> 的一样。
    <code>name</code> 是代码块的名字，用于调试信息和错误消息。
    字符串 <code>mode</code> 和函数 <a href="#lua_load"><code>lua_load</code></a> 中的一样。

    <hr />
    <h3><a name="luaL_loadfile"><code>luaL_loadfile</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>int luaL_loadfile (lua_State *L, const char *filename);</pre>

    <p />
    等价于 <code>mode</code> 为 <code>NULL</code> 的 <a href="#luaL_loadfilex"><code>luaL_loadfilex</code></a>。

    <hr />
    <h3><a name="luaL_loadfilex"><code>luaL_loadfilex</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>int luaL_loadfilex (lua_State *L, const char *filename,
                                            const char *mode);</pre>

    <p />
    将文件加载为 Lua 代码块。
    函数使用 <a href="#lua_load"><code>lua_load</code></a> 加载名为 <code>filename</code> 的文件的代码块。
    如果 <code>filename</code> 为 <code>NULL</code>,它会从标准输入中加载。
    如果它第一行以 <code>#</code> 开头，则该行会被忽略。

    <p />
    字符串 <code>mode</code> 和函数 <a href="#lua_load"><code>lua_load</code></a> 中的一样。

    <p />
    函数返回结果和 as <a href="#lua_load"><code>lua_load</code></a> 的一样，或当文件相关操作错误时返回 <a
        href="#pdf-LUA_ERRFILE"><code>LUA_ERRFILE</code></a>。

    <p />
    和 <a href="#lua_load"><code>lua_load</code></a> 一样,函数只是加载代码块，而不会运行它。

    <hr />
    <h3><a name="luaL_loadstring"><code>luaL_loadstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>int luaL_loadstring (lua_State *L, const char *s);</pre>

    <p />
    加载字符串为 Lua 代码块。
    函数使用 <a href="#lua_load"><code>lua_load</code></a> 加载零结尾字符串 <code>s</code> 的代码块。

    <p />
    函数返回结果和 <a href="#lua_load"><code>lua_load</code></a> 的一样。

    <p />
    和 <a href="#lua_load"><code>lua_load</code></a> 一样,函数只是加载代码块，而不会运行它。

    <hr />
    <h3><a name="luaL_newlib"><code>luaL_newlib</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void luaL_newlib (lua_State *L, const luaL_Reg l[]);</pre>

    <p />
    创建一个新表并注册列表 <code>l</code> 中的函数。

    <p />
    它以下面宏的形式实现：

    <pre>
     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
</pre>
    <p />
    数组 <code>l</code> 必须为一个真实的数组，而不能是一个指向它的指针。

    <hr />
    <h3><a name="luaL_newlibtable"><code>luaL_newlibtable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);</pre>

    <p />
    使用优化过的大小创建一个新表以存储数组 <code>l</code> 中的所有条目(但实际并不会存储它们)。
    它的目的是与 <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> 结合使用(参见 <a href="#luaL_newlib"><code>luaL_newlib</code></a>)。

    <p />
    它以宏的形式实现。
    数组 <code>l</code> 必须为一个真实的数组，而不能是一个指向它的指针。

    <hr />
    <h3><a name="luaL_newmetatable"><code>luaL_newmetatable</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>int luaL_newmetatable (lua_State *L, const char *tname);</pre>

    <p />
    如果注册表中已经存在 <code>tname</code> 键，返回 0。
    否则， 创建一个用于用户数据元表的新表。
    在这个新表中添加键值对 <code>__name = tname</code>,
    注册表中添加键值对 <code>[tname] = new table</code>,
    并返回 1。

    <p />
    在这两种情况下，该函数都会将注册表中与 <code>tname</code> 相关联的最终值压入栈。

    <hr />
    <h3><a name="luaL_newstate"><code>luaL_newstate</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>lua_State *luaL_newstate (void);</pre>

    <p />
    创建一个新的 Lua 状态机。
    它设置一个警告函数，并通过一个基于 ISO C 分配函数的内存分配器和一个打印信息到标准错误输出的应急函数(参见 <a href="#4.4">&sect;4.4</a>) 来调用 <a
        href="#lua_newstate"><code>lua_newstate</code></a> 。

    <p />
    返回该新状态机，或在内存分配错误时返回 <code>NULL</code>。

    <hr />
    <h3><a name="luaL_openlibs"><code>luaL_openlibs</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>e</em>]</span>
    <pre>void luaL_openlibs (lua_State *L);</pre>

    <p />
    打开给定状态机中的所有标准 Lua 库。

    <hr />
    <h3><a name="luaL_opt"><code>luaL_opt</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>T luaL_opt (L, func, arg, dflt);</pre>

    <p />
    宏定义如下：

    <pre>
     (lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))
</pre>
    <p />
    如果函数第 <code>arg</code> 个参数为 nil 或缺省, 宏结果为默认值 <code>dflt</code>。
    否则, 它将返回通过状态机 <code>L</code> 和索引 <code>arg</code> 为参数调用 <code>func</code> 的结果
    注意，它只在需要的时候检测表达式 <code>dflt</code>。

    <hr />
    <h3><a name="luaL_optinteger"><code>luaL_optinteger</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>lua_Integer luaL_optinteger (lua_State *L,
                             int arg,
                             lua_Integer d);</pre>

    <p />
    如果函数第 <code>arg</code> 个参数为一个整数(或者它可以转换为一个整数)，返回这个整数。
    如果参数缺省或为 <b>nil</b>, 返回 <code>d</code>。
    否则，抛出错误。

    <hr />
    <h3><a name="luaL_optlstring"><code>luaL_optlstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>const char *luaL_optlstring (lua_State *L,
                             int arg,
                             const char *d,
                             size_t *l);</pre>

    <p />
    如果函数第 <code>arg</code> 个参数为一个字符串，返回这个字符串。
    如果参数缺省或为 <b>nil</b>, 返回 <code>d</code>。
    否则，抛出错误。

    <p />
    如果 <code>l</code> 不为 <code>NULL</code>，用结果的长度填充其引用。
    如果结果为 <code>NULL</code>
    (只发生在返回 <code>d</code> 并且 <code>d == NULL</code> 时),
    它的长度被认为是零。

    <p />
    函数使用 <a href="#lua_tolstring"><code>lua_tolstring</code></a> 以获取它的结果，
    因此该函数的所有转换和注意事项都适用于此。

    <hr />
    <h3><a name="luaL_optnumber"><code>luaL_optnumber</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);</pre>

    <p />
    如果函数第 <code>arg</code> 个参数为一个数字，将这个数字作为一个 <code>lua_Number</code> 返回。
    如果参数缺省或为 <b>nil</b>, 返回 <code>d</code>。
    否则，抛出错误。

    <hr />
    <h3><a name="luaL_optstring"><code>luaL_optstring</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>const char *luaL_optstring (lua_State *L,
                            int arg,
                            const char *d);</pre>

    <p />
    如果函数第 <code>arg</code> 个参数为一个字符串，返回这个字符串。
    如果参数缺省或为 <b>nil</b>, 返回 <code>d</code>。
    否则，抛出错误。

    <hr />
    <h3><a name="luaL_prepbuffer"><code>luaL_prepbuffer</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>char *luaL_prepbuffer (luaL_Buffer *B);</pre>

    <p />
    等价于使用预定义尺寸 <a name="pdf-LUAL_BUFFERSIZE"><code>LUAL_BUFFERSIZE</code></a> 的 <a
        href="#luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a>。

    <hr />
    <h3><a name="luaL_prepbuffsize"><code>luaL_prepbuffsize</code></a></h3>
    <p />
    <span class="apii">[-?, +?, <em>m</em>]</span>
    <pre>char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);</pre>

    <p />
    返回一段大小为 <code>sz</code> 的空间地址，你可以将字符串复制其中以加到缓存 <code>B</code>(参见 <a
        href="#luaL_Buffer"><code>luaL_Buffer</code></a>) 内。
    字符串赋值到这段空间后你必须使用字符串的大小调用 <a href="#luaL_addsize"><code>luaL_addsize</code></a> 以把它真正地添加到缓冲。

    <hr />
    <h3><a name="luaL_pushfail"><code>luaL_pushfail</code></a></h3>
    <p />
    <span class="apii">[-0, +1, &ndash;]</span>
    <pre>void luaL_pushfail (lua_State *L);</pre>

    <p />
    压入一个 <b>fail</b> 值到栈中 (参见 <a href="#6">&sect;6</a>)。

    <hr />
    <h3><a name="luaL_pushresult"><code>luaL_pushresult</code></a></h3>
    <p />
    <span class="apii">[-?, +1, <em>m</em>]</span>
    <pre>void luaL_pushresult (luaL_Buffer *B);</pre>

    <p />
    结束缓冲 <code>B</code> 的使用并将最终字符串留在栈顶。

    <hr />
    <h3><a name="luaL_pushresultsize"><code>luaL_pushresultsize</code></a></h3>
    <p />
    <span class="apii">[-?, +1, <em>m</em>]</span>
    <pre>void luaL_pushresultsize (luaL_Buffer *B, size_t sz);</pre>

    <p />
    等价于顺序调用 <a href="#luaL_addsize"><code>luaL_addsize</code></a>, <a
        href="#luaL_pushresult"><code>luaL_pushresult</code></a>。

    <hr />
    <h3><a name="luaL_ref"><code>luaL_ref</code></a></h3>
    <p />
    <span class="apii">[-1, +0, <em>m</em>]</span>
    <pre>int luaL_ref (lua_State *L, int t);</pre>

    <p />
    为栈顶对象(最后会被弹出)创建并返回一个索引 <code>t</code> 处的表的 <em>reference(引用)</em>。

    <p />
    引用是一个唯一的整数键。
    只要你不手动添加整数键至表 <code>t</code> 中, <a href="#luaL_ref"><code>luaL_ref</code></a> 确保它返回的键的唯一性。
    你可以调用 <code>lua_rawgeti(L, t, r)</code> 来获取 <code>r</code> 引用的对象。
    函数 <a href="#luaL_unref"><code>luaL_unref</code></a> 释放引用。

    <p />
    如果栈顶对象是 <b>nil</b>, <a href="#luaL_ref"><code>luaL_ref</code></a> 返回常量 <a
        name="pdf-LUA_REFNIL"><code>LUA_REFNIL</code></a>。
    常量 <a name="pdf-LUA_NOREF"><code>LUA_NOREF</code></a> 保证与其它所有从 <a href="#luaL_ref"><code>luaL_ref</code></a> 的返回值不同。

    <hr />
    <h3><a name="luaL_Reg"><code>luaL_Reg</code></a></h3>
    <pre>typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;</pre>

    <p />
    用于 <a href="#luaL_setfuncs"><code>luaL_setfuncs</code></a> 注册的函数数组类型。
    <code>name</code> 为函数名，<code>func</code> 为函数指针。
    所有 <a href="#luaL_Reg"><code>luaL_Reg</code></a> 数组都必须以一个 <code>name</code> 和 <code>func</code> 都为 <code>NULL</code>
    的哨兵条目结尾。

    <hr />
    <h3><a name="luaL_requiref"><code>luaL_requiref</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>void luaL_requiref (lua_State *L, const char *modname,
                    lua_CFunction openf, int glb);</pre>

    <p />
    如果 <code>package.loaded[modname]</code> 不为 true,
    将 <code>modname</code> 作为参数调用函数 <code>openf</code> 并将其结果设置到 <code>package.loaded[modname]</code>，
    就好像这个函数是通过 <a href="#pdf-require"><code>require</code></a> 调用的。

    <p />
    如果 <code>glb</code> 为 true，也会将模块设置到全局变量 <code>modname</code>。

    <p />
    在栈上留下模块的副本。

    <hr />
    <h3><a name="luaL_setfuncs"><code>luaL_setfuncs</code></a></h3>
    <p />
    <span class="apii">[-nup, +0, <em>m</em>]</span>
    <pre>void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);</pre>

    <p />
    将数组 <code>l</code> (参见 <a href="#luaL_Reg"><code>luaL_Reg</code></a>) 中的所有函数注册到栈顶的表中。
    (该表在可选的上值之下，详情见下面解说)。

    <p />
    当 <code>nup</code> 不为 0 时,
    所有的函数都共享 <code>nup</code> 个上值。
    这些值必须在调用之前，压在表之上。
    这些值在注册完毕后都会从栈弹出。

    <p />
    具有 <code>NULL</code> 值的函数表示占位符，它使用 <b>false</b> 填充。

    <hr />
    <h3><a name="luaL_setmetatable"><code>luaL_setmetatable</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void luaL_setmetatable (lua_State *L, const char *tname);</pre>

    <p />
    设置栈顶对象的元表为注册表中与名字 <code>tname</code> 相关联的元表(参见 <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>)。

    <hr />
    <h3><a name="luaL_Stream"><code>luaL_Stream</code></a></h3>
    <pre>typedef struct luaL_Stream {
  FILE *f;
  lua_CFunction closef;
} luaL_Stream;</pre>

    <p />
    用于标准 I/O 库的文件句柄的标准表示。

    <p />
    文件句柄被实现为完全用户数据，它有一个称为 <code>LUA_FILEHANDLE</code>(一个代表真正元表名字的宏)的元表。
    元表由 I/O 库创建(参见 <a href="#luaL_newmetatable"><code>luaL_newmetatable</code></a>)。

    <p />
    这个用户数据必须以结构体 <code>luaL_Stream</code> 开头;
    初始化结构体之后，它可以包含其它数据。
    字段 <code>f</code> 指向相应的 C 数据流(或为 <code>NULL</code> 表示一个没有创建好的句柄)。
    字段 <code>closef</code> 指向一个当句柄已经被关闭或收集时将被调用以关闭数据流的 Lua 函数;
    函数接收文件句柄作为它的唯一参数并且必须在操作成功时返回一个真值，或在出错是返回一个假值加上一个错误消息。
    每当 Lua 调用这个字段，它都会将这个字段的值改为 <code>NULL</code> 以标记句柄已经被关闭。

    <hr />
    <h3><a name="luaL_testudata"><code>luaL_testudata</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>m</em>]</span>
    <pre>void *luaL_testudata (lua_State *L, int arg, const char *tname);</pre>

    <p />
    函数和 <a href="#luaL_checkudata"><code>luaL_checkudata</code></a> 类似,
    不同的是，当检测失败，它返回 <code>NULL</code> 而不是抛出错误。

    <hr />
    <h3><a name="luaL_tolstring"><code>luaL_tolstring</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>e</em>]</span>
    <pre>const char *luaL_tolstring (lua_State *L, int idx, size_t *len);</pre>

    <p />
    将 idx 处的 Lua 值转换为相应格式的 C 字符串。
    将结果压入栈并返回 (参见 <a href="#4.1.3">&sect;4.1.3</a>)。
    如果 <code>len</code> 为 <code>NULL</code>,
    函数还会设置 <code>*len</code> 为字符串长度。

    <p />
    如果值有一个带有 <code>__tostring</code> 字段的元表，<code>luaL_tolstring</code> 使用该值作为参数调用相应的元方法并将调用结果作为返回值。

    <hr />
    <h3><a name="luaL_traceback"><code>luaL_traceback</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                     int level);</pre>

    <p />
    创建栈 <code>L1</code> 的回溯信息并将其压入栈。
    如果 <code>msg</code> 不为 <code>NULL</code>, 它被添加到回溯信息的开头。
    <code>level</code> 表明回溯信息从哪层开始。

    <hr />
    <h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3>
    <p />
    <span class="apii">[-0, +0, <em>v</em>]</span>
    <pre>int luaL_typeerror (lua_State *L, int arg, const char *tname);</pre>

    <p />
    使用标准信息为调用 C 函数的第 <code>arg</code> 个参数抛出一个类型错误。
    <code>tname</code> 为期望类型的名字。
    函数不会返回。

    <hr />
    <h3><a name="luaL_typename"><code>luaL_typename</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>const char *luaL_typename (lua_State *L, int index);</pre>

    <p />
    返回 index 处的值的类型的名字。

    <hr />
    <h3><a name="luaL_unref"><code>luaL_unref</code></a></h3>
    <p />
    <span class="apii">[-0, +0, &ndash;]</span>
    <pre>void luaL_unref (lua_State *L, int t, int ref);</pre>

    <p />
    释放索引 <code>t</code> 处的表的 <code>ref</code> 引用。
    (参见 <a href="#luaL_ref"><code>luaL_ref</code></a>).
    该条目将从表中移除，因此引用对象可以被收集。
    而 <code>ref</code> 也被回收以再次使用。

    <p />
    如果 <code>ref</code> 为 <a href="#pdf-LUA_NOREF"><code>LUA_NOREF</code></a> 或 <a
        href="#pdf-LUA_REFNIL"><code>LUA_REFNIL</code></a>,
    <a href="#luaL_unref"><code>luaL_unref</code></a> 什么也不会做。

    <hr />
    <h3><a name="luaL_where"><code>luaL_where</code></a></h3>
    <p />
    <span class="apii">[-0, +1, <em>m</em>]</span>
    <pre>void luaL_where (lua_State *L, int lvl);</pre>

    <p />
    将调用栈中层级 <code>lvl</code> 的控制点当前位置的字符串唯一标识压入栈。
    通常，这个字符串有以下格式:

    <pre>
     <em>chunkname</em>:<em>currentline</em>:
</pre>
    <p />
    层级 0 为当前运行的函数，
    层级 1 为调用当前函数的函数，
    等等...

    <p />
    函数用于构建错误消息的前缀。

    <h1>6 &ndash; <a name="6">标准库</a></h1>

    <p />
    标准 Lua 库提供了通过 C API 在 C 中实现的实用函数。
    其中一些函数为语言提供基本服务(例如，<a href="#pdf-type"><code>type</code></a> 和 <a href="#pdf-getmetatable"><code>getmetatable</code></a>)
    还有一些提供了对外部服务的访问(例如，I/O)；
    其它的可以在 Lua 中实现，
    但由于不同原因，在 C 中实现(例如，<a href="#pdf-table.sort"><code>table.sort</code></a>)。

    <p />
    所有的都通过官方 C API 实现并作为单独的 C 模块提供。
    除非另有说明, 这些库函数不会将实参的个数调整为形参个数。
    例如, 文档 <code>foo(arg)</code> 的函数不应该在没有参数的情况下使用。

    <p />
    符号 <b>fail</b> 表示表示某种失败的假值。
    (目前, <b>fail</b> 等于 <b>nil</b>, 但可能在未来版本中改变。
    建议总是使用<code>(not status)</code>来测试这些函数的成功，而不是使用<code>(status == nil)</code>。

    <p />
    目前, Lua 有以下标准库:

    <ul>
        <li>basic library(基础库) (<a href="#6.1">&sect;6.1</a>)</li>
        <li>coroutine library(协程库) (<a href="#6.2">&sect;6.2</a>)</li>
        <li>package library(包库) (<a href="#6.3">&sect;6.3</a>)</li>
        <li>string manipulation(字符串操作库) (<a href="#6.4">&sect;6.4</a>)</li>
        <li>basic UTF-8 support(基础 UTF-8 库) (<a href="#6.5">&sect;6.5</a>)</li>
        <li>table manipulation(表库) (<a href="#6.6">&sect;6.6</a>)</li>
        <li>mathematical functions(数学库) (<a href="#6.7">&sect;6.7</a>) (sin, log, etc.)</li>
        <li>input and output(输入输出库) (<a href="#6.8">&sect;6.8</a>)</li>
        <li>operating system facilities(操作系统库) (<a href="#6.9">&sect;6.9</a>)</li>
        <li>debug facilities(调试库) (<a href="#6.10">&sect;6.10</a>)</li>
    </ul>
    <p />
    除了标准库和包库,每个库都将其函数作为全局表的字段或其对象的方法提供。

    <p />
    要访问这些库, 宿主 C 程序需要先调用 <a href="#luaL_openlibs"><code>luaL_openlibs</code></a> 函数(它打开所有的标准库)，
    或者, 宿主程序可以调用 <a href="#luaL_requiref"><code>luaL_requiref</code></a>,
    <a name="pdf-luaopen_base"><code>luaopen_base</code></a> (基础库),
    <a name="pdf-luaopen_package"><code>luaopen_package</code></a> (包库),
    <a name="pdf-luaopen_coroutine"><code>luaopen_coroutine</code></a> (协程库),
    <a name="pdf-luaopen_string"><code>luaopen_string</code></a> (字符串库),
    <a name="pdf-luaopen_utf8"><code>luaopen_utf8</code></a> (UTF-8 库),
    <a name="pdf-luaopen_table"><code>luaopen_table</code></a> (表库),
    <a name="pdf-luaopen_math"><code>luaopen_math</code></a> (数学库),
    <a name="pdf-luaopen_io"><code>luaopen_io</code></a> (I/O 库),
    <a name="pdf-luaopen_os"><code>luaopen_os</code></a> (操作系统库),
    <a name="pdf-Lua open_debug"><code>luaopen_debug</code></a> (调试库)
    分别打开它们。
    这些函数定义在 <a name="pdf-Lua lib.h"><code>lualib.h</code></a> 中。

    <h2>6.1 &ndash; <a name="6.1">基础函数</a></h2>

    <p />
    基础库提供 Lua 的核心函数。
    如果你不将这个库包含在你的程序中，则应该仔细检查是否需要为它的某些功能提供实现。

    <p />
    <hr />
    <h3><a name="pdf-assert"><code>assert (v [, message])</code></a></h3>

    <p />
    如果参数 <code>v</code> 的值为假(即, <b>nil</b> 或 <b>false</b>)则抛出错误;
    否则, 返回它的所有参数。
    发生错误时, <code>message</code> 为错误对象;
    如果缺省, 则默认为 "<code>assertion failed!</code>"。

    <hr />
    <h3><a name="pdf-collectgarbage"><code>collectgarbage ([opt [, arg]])</code></a></h3>

    <p />
    函数时垃圾收集器的通用函数。
    它根据第一个参数 <code>opt</code> 的不同执行不同的操作:
    <ul>
        <li><b>"<code>collect</code>": </b>
            执行一次完整的垃圾收集周期。
            这是默认选项。
        </li>

        <li><b>"<code>stop</code>": </b>
            停止垃圾收集的自动收集。
            收集器只在显式调用才会执行，直到重启它。
        </li>

        <li><b>"<code>restart</code>": </b>
            重新启用垃圾收集的自动执行。
        </li>

        <li><b>"<code>count</code>": </b>
            以 K 字节为单位返回 Lua 中使用的总内存。
            该值有小数部分，因此它乘以 1024 就得到了 Lua 所使用的确切字节数。
        </li>

        <li><b>"<code>step</code>": </b>
            执行一个垃圾收集步骤。
            步长“大小”由 <code>arg</code> 控制。
            如果为 0, 收集器执行一个基础(不可分割的)步骤。
            为非 0 值时，收集器将收集 Lua 分配的对应数量的内存(以 K 字节为单位)。
            如果收集器结束一个收集周期则返回 <b>true</b>。
        </li>

        <li><b>"<code>isrunning</code>": </b>
            返回表明收集器是否正在运行(即，没有停止)的布尔值。
        </li>

        <li><b>"<code>incremental</code>": </b>
            修改收集器模式为增量模式。
            选项后可以跟三个数字: 垃圾收集间歇率, 步进倍率和步长(参见 <a href="#2.5.1">&sect;2.5.1</a>)。
            一个单独的 0 表示不修改这些值。
        </li>

        <li><b>"<code>generational</code>": </b>
            修改收集器模式为分代模式。
            选项后可以跟两个数字: 垃圾收集次要倍率和主要倍率 (参见 <a href="#2.5.2">&sect;2.5.2</a>)。
            一个单独的 0 表示不修改这些值。
        </li>
    </ul>
    <p />
    参见 <a href="#2.5">&sect;2.5</a> 以了解关于垃圾收集和这些选项的更多细节。

    <p />
    函数不应该被终结器调用。

    <p />
    <hr />
    <h3><a name="pdf-dofile"><code>dofile ([filename])</code></a></h3>
    打开对应名字的文件并将其内容作为 Lua 代码块执行。
    当没有参数时, <code>dofile</code> 执行标准输入 (<code>stdin</code>) 的内容。
    返回代码块返回的所有值。
    如果发生错误, <code>dofile</code> 将错误传播到它的调用者。
    (即, <code>dofile</code> 没有在保护模式中调用)

    <p />
    <hr />
    <h3><a name="pdf-error"><code>error (message [, level])</code></a></h3>
    将 <code>message</code> 作为错误对象抛出一个错误 (参见 <a href="#2.3">&sect;2.3</a>)。
    函数不会返回。

    <p />
    通常, 如果 <code>message</code> 为字符串，<code>error</code> 在消息的开头添加一些关于错误位置的信息，
    参数 <code>level</code> 指定获取错误位置的层数。
    层数 0 表示获取调用 <code>error</code> 的位置。
    层数 1 表示获取调用 <code>error</code> 的函数的位置。
    层数 2 表示获取调用 <code>error</code> 的函数的调用者的位置，等等。
    传递层数 0 避免在消息中添加错误位置信息。

    <p />
    <hr />
    <h3><a name="pdf-_G"><code>_G</code></a></h3>
    保存全局环境(参见 <a href="#2.2">&sect;2.2</a>)的全局变量 (不是函数)。
    Lua 自身不会使用这个变量。
    更改其值不会影响任何环境，反之亦然。

    <p />
    <hr />
    <h3><a name="pdf-getmetatable"><code>getmetatable (object)</code></a></h3>

    <p />
    如果 <code>object</code> 没有元表, 返回 <b>nil</b>。
    否则, 如果它的元表有 <code>__metatable</code> 字段，返回对应值。
    否则返回给定对象的元表。

    <p />
    <hr />
    <h3><a name="pdf-ipairs"><code>ipairs (t)</code></a></h3>

    <p />
    返回三个值 (一个迭代器函数, 表 <code>t</code>, 和 0)
    因此，如下代码：

    <pre>
     for i,v in ipairs(t) do <em>body</em> end
</pre>
    <p />
    将迭代键值对(<code>1,t[1]</code>) ，(<code>2,t[2]</code>)， ... ，直到第一个空值。

    <p />
    <hr />
    <h3><a name="pdf-load"><code>load (chunk [, chunkname [, mode [, env]]])</code></a></h3>

    <p />
    加载一个代码块。

    <p />
    如果 <code>chunk</code> 是一个字符串, 代码块就是这个字符串。
    如果 <code>chunk</code> 是一个函数, <code>load</code> 反复调用它以获取代码块片段。
    每次调用 <code>chunk</code> 必须返回一个与先前结果连接的字符串。
    返回一个空字符串、 <b>nil</b>、 或没有值返回表示代码块的结尾。

    <p />
    如果没有语法错误, <code>load</code> 将编译的代码块作为一个函数返回；
    否则, 它返回 <b>fail</b> 加上错误信息。

    <p />
    当你加载一个主代码块时，结果函数总是包含一个上值(<code>_ENV</code> 变量(参见 <a href="#2.2">&sect;2.2</a>))。
    然而，当你加载一个由函数 (参见 <a href="#pdf-string.dump"><code>string.dump</code></a>) 创建的二进制块时，
    结果函数可以包含任意数量的上值并不能确保它的第一个上值为 <code>_ENV</code> 变量(一个非主函数甚至可能没有 <code>_ENV</code> 上值)。

    <p />
    无论如何，如果生成的函数有任何上值，将其第一个上值设置为 <code>env</code> 的值(如果给出了这个参数)或者设置为全局环境的值。
    其他上值被初始化为 <b>nil</b>。
    所有的上值都是新的，也就是说，他们不会与其他函数共享。

    <p />
    <code>chunkname</code> 用于错误信息和调试信息(参见 <a href="#4.7">&sect;4.7</a>)中作为代码块的名字。
    如果缺省，在 <code>chunk</code> 是一个字符串时，默认值为 <code>chunk</code> 的值，
    否则为 "<code>=(load)</code>"。

    <p />
    字符串 <code>mode</code> 控制代码块时文本还是二进制(即，预编译代码块)。
    他可能是字符串 "<code>b</code>" (只能是二进制块), "<code>t</code>" (只能是文本) 或 "<code>bt</code>" (可以是二进制或文本)。
    默认为 "<code>bt</code>"。

    <p />
    加载格式错误的二进制块是安全的:
    <code>load</code> 会标记对应的错误。
    然而, Lua 不会检测二进制代码块的健壮性;
    运行恶意编写的字节码可能会使解释器崩溃。

    <p />
    <hr />
    <h3><a name="pdf-loadfile"><code>loadfile ([filename [, mode [, env]]])</code></a></h3>

    <p />
    和 <a href="#pdf-load"><code>load</code></a> 类似, 但是代码块来自于文件 <code>filename</code>，没有给出文件名时为标准输入。

    <p />
    <hr />
    <h3><a name="pdf-next"><code>next (table [, index])</code></a></h3>

    <p />
    允许程序遍历一个表的所有字段。
    它的第一个参数是一个表，第二个参数是表中的一个索引。
    对<code>next</code>的调用返回表的下一个索引及其关联的值。
    当把 <b>nil</b> 作为第二个参数来调用时，<code>next</code> 返回一个初始索引和其关联的值，
    当使用最后一个索引, 或空表中使用 <b>nil</b> 调用时, <code>next</code> 返回 <b>nil</b>。
    如果缺省第二个参数，它将被解释为 <b>nil</b>。
    特别地，你可以使用 <code>next(t)</code> 以检测一个表是否为空。

    <p />
    <em>即使是数字索引</em>，索引的枚举顺序也没有指定(要按数字顺序遍历表，请使用数字 <b>for</b>)。

    <p />
    在表的遍历过程中，不应该给表中不存在的字段赋值。
    但你可以修改现有字段。
    特别地, 你可以修改现有字段为 nil。

    <p />
    <hr />
    <h3><a name="pdf-pairs"><code>pairs (t)</code></a></h3>

    <p />
    如果 <code>t</code> 有元方法 <code>__pairs</code>，以 <code>t</code> 为参数调用它，并返回其返回的前三个值。

    <p />
    否则返回三个值: <a href="#pdf-next"><code>next</code></a> 函数, 表 <code>t</code> 和 <b>nil</b>， 因此一下代码：

    <pre>
     for k,v in pairs(t) do <em>body</em> end
</pre>
    <p />
    将迭代表 <code>t</code> 中的所有键值对。

    <p />
    参见 <a href="#pdf-next"><code>next</code></a> 以了解遍历表时修改表的注意事项。

    <p />
    <hr />
    <h3><a name="pdf-pcall"><code>pcall (f [, arg1, &middot;&middot;&middot;])</code></a></h3>

    <p />
    在 <em>保护模式</em> 中通过给定参数调用函数 <code>f</code>。
    这意味着 <code>f</code> 中发生的所有错误都不会被传播; 取而代之的是, <code>pcall</code> 捕获错误并且返回一个状态码。
    函数的第一个返回值是一个状态码(一个布尔值), 如果调用没有错误则为 <b>true</b>。
    在这种情况中, <code>pcall</code> 也返回调用中的所有返回值, 它们在第一个返回值之后。
    如果发生错误, <code>pcall</code> 返回 <b>false</b> 加上错误对象。
    注意， <code>pcall</code> 捕获的错误不会调用消息处理器。

    <p />
    <hr />
    <h3><a name="pdf-print"><code>print (&middot;&middot;&middot;)</code></a></h3>
    接收任意数量的参数并且将它们以 <a href="#pdf-tostring"><code>tostring</code></a> 一样的规则转换为字符串打印到 <code>stdout(标准输出)</code>。

    <p />
    函数 <code>print</code> 不是用于格式化输出，而只是作为快速显示值的方法，例如用于调试。
    要完全控制输出, 请使用 <a href="#pdf-string.format"><code>string.format</code></a> 和 <a href="#pdf-io.write"><code>io.write</code></a>。

    <p />
    <hr />
    <h3><a name="pdf-rawequal"><code>rawequal (v1, v2)</code></a></h3>
    不调用 <code>__eq</code> 元方法，检测 <code>v1</code> 是否等于 <code>v2</code>。
    返回一个布尔值。

    <p />
    <hr />
    <h3><a name="pdf-rawget"><code>rawget (table, index)</code></a></h3>
    不使用 <code>__index</code> 元值，获取 <code>table[index]</code> 的真实值。
    <code>table</code> 必须是一个表，
    <code>index</code> 可以是任何值。

    <p />
    <hr />
    <h3><a name="pdf-rawlen"><code>rawlen (v)</code></a></h3>
    不调用 <code>__len</code> 元方法，返回 <code>v</code>(他必须是一个表/字符串) 长度。
    返回一个整数。

    <p />
    <hr />
    <h3><a name="pdf-rawset"><code>rawset (table, index, value)</code></a></h3>
    不使用 <code>__newindex</code> 元值，设置 <code>table[index]</code> 的值为 <code>value</code>。
    <code>table</code> 必须是一个表，
    <code>index</code> 是 <b>nil</b> 和 NaN 之外的任何值，
    <code>value</code> 是任意 Lua 值。

    <p />
    函数返回 <code>table</code>。

    <p />
    <hr />
    <h3><a name="pdf-select"><code>select (index, &middot;&middot;&middot;)</code></a></h3>

    <p />
    如果 <code>index</code> 是个数字，那么返回参数中第 <code>index</code> 个之后的部分；
    负的数字会从后向前索引(-1 指最后一个参数)。
    否则，<code>index</code> 必须是字符串 <code>"#"</code>，此时 <code>select</code> 返回参数的个数。

    <p />
    <hr />
    <h3><a name="pdf-setmetatable"><code>setmetatable (table, metatable)</code></a></h3>

    <p />
    为给定表设置元表。
    如果 <code>metatable</code> 为 <b>nil</b>, 移除给定表的元表。
    如果初始元表有 <code>__metatable</code> field, 抛出错误。

    <p />
    函数返回 <code>table</code>。

    <p />
    要在 Lua 代码中更改其他类型的元表，必须使用调试库 (<a href="#6.10">&sect;6.10</a>)。

    <p />
    <hr />
    <h3><a name="pdf-tonumber"><code>tonumber (e [, base])</code></a></h3>

    <p />
    如果调用时没有 <code>base</code>, <code>tonumber</code> 尝试将参数转换为数字。
    如果参数是一个数字或可以转换成数字的字符串, <code>tonumber</code> 返回这个数字;
    否则, 返回 <b>fail</b>。

    <p />
    字符串转换结果可能是整数或浮点数，这取决于 Lua 的转换词法(参见 <a href="#3.1">&sect;3.1</a>)。
    字符串可以有前置或后置空格和一个符号。

    <p />
    当调用时包含 <code>base</code> 参数, <code>e</code> 必须是需要在改进制下要解释为一个整数的字符串。
    进制数在 <b>[2-36]</b> 之间。
    大于 10 的进制中, 字母 '<code>A</code>' (不区分大消息) 代表 10, '<code>B</code>' 代表 11, 等等, '<code>Z</code>' 代表 35。
    如果字符串 <code>e</code> 在给定进制中不是一个有效数字, 函数返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-tostring"><code>tostring (v)</code></a></h3>

    <p />
    接收一个任意类型的值并将其转换为人类可读格式的字符串。

    <p />
    如果 <code>v</code> 的元表有 <code>__tostring</code> 字段, <code>tostring</code> 将 <code>v</code> 作为参数调用对应值并使用调用结果作为其结果。
    否则, 如果 <code>v</code> 的元表有 <code>__name</code> 字段(一个字符串), <code>tostring</code> 用这个字符串作为它的最终返回值。

    <p />
    要完全控制数字的转换方式，请使用 <a href="#pdf-string.format"><code>string.format</code></a>.

    <p />
    <hr />
    <h3><a name="pdf-type"><code>type (v)</code></a></h3>

    <p />
    将参数的类型编码为一个字符串以返回。可能的结果有
    "<code>nil</code>",
    "<code>number</code>",
    "<code>string</code>",
    "<code>boolean</code>",
    "<code>table</code>",
    "<code>function</code>",
    "<code>thread</code>",
    "<code>userdata</code>"。

    <p />
    <hr />
    <h3><a name="pdf-_VERSION"><code>_VERSION</code></a></h3>

    <p />
    存储运行的 Lua 版本的字符串全局变量 (不是一个函数) 。
    这个变量的当前值为 "<code>Lua 5.4</code>"。

    <p />
    <hr />
    <h3><a name="pdf-warn"><code>warn (msg1, &middot;&middot;&middot;)</code></a></h3>

    <p />
    发出一条由其所有参数(应该是字符串)拼接而成的消息的警告。

    <p />
    按照惯例, 以 '<code>@</code>' 开头的消息表示一个 <em>control message(控制消息)</em>, 这是警告系统本身的消息。
    特别地, Lua 中的标准警告函数识别控制消息 "<code>@off</code>" 以关闭警告，"<code>@on</code>" 以打开警告。
    它会忽略未知的控制消息。

    <p />
    <hr />
    <h3><a name="pdf-xpcall"><code>xpcall (f, msgh [, arg1, &middot;&middot;&middot;])</code></a></h3>

    <p />
    函数与 <a href="#pdf-pcall"><code>pcall</code></a> 类似, 不同的是它使用新的消息处理器 <code>msgh</code>.

    <h2>6.2 &ndash; <a name="6.2">协程操作</a></h2>

    <p />
    该库包含操作协程的操作，这些操作位于表 <a name="pdf-coroutine"><code>coroutine</code></a> 中。
    参见 <a href="#2.6">&sect;2.6</a> 了解协程。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.close"><code>coroutine.close (co)</code></a></h3>

    <p />
    关闭协程 <code>co</code> (即关闭它的所有暂定的待关闭变量并将协程置于死亡状态)。
    给定协程必须已经死亡或挂起。
    发生错误(停止协程的原始错误或关闭方法中的错误)时返回 <b>false</b> 加上错误对象；否则返回 <b>true</b>。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.create"><code>coroutine.create (f)</code></a></h3>

    <p />
    使用主体函数 <code>f</code> 创建一个协程。
    <code>f</code> 必须是一个函数。
    返回一个类型为 <code>"thread"</code> 新协程。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.isyieldable"><code>coroutine.isyieldable ([co])</code></a></h3>

    <p />
    当协程 <code>co</code> 可以让出时返回 <b>true</b>。
    <code>co</code> 默认为当前运行的协程。

    <p />
    不在主线程中并且不在不可让出的 C 函数中，那么这个协程就是可让出的。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.resume"><code>coroutine.resume (co [, val1, &middot;&middot;&middot;])</code></a>
    </h3>

    <p />
    启动或延续协程 <code>co</code> 的执行。
    第一次 resume 一个协程的时候，它启动它的主体函数。
    值 <code>val1</code>, ... 作为参数传入主体函数。
    如果函数已经让出，<code>resume</code> 延续它的执行;
    值 <code>val1</code>, ... 作为参数从让出的结果返回。

    <p />
    如果协程运行没有错误，<code>resume</code> 返回 <b>true</b> 加上传递给 <code>yield</code> 的所有值(当协程让出)或从主体函数返回的所有值(当协程终结)。
    如果发生错误, <code>resume</code> 返回 <b>false</b> 加上错误信息。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.running"><code>coroutine.running ()</code></a></h3>

    <p />
    返回当前运行的协程和一个布尔值，当运行的协程为主协程时为 <b>true</b>。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.status"><code>coroutine.status (co)</code></a></h3>

    <p />
    将 <code>co</code> 的状态作为一个字符串返回：
    如果协程正在运行则为 <code>"running"</code>,
    (即，它就是调用 <code>status</code> 的那个);
    如果协程调用 <code>yield</code> 挂起了或还没有开始运行则为 <code>"suspended"</code>；
    如果协程活跃但是没有运行(即，它正在延续了另一个协程) <code>"normal"</code>；
    如果协程完成了它的主体函数，或它在错误中停止则为 <code>"dead"</code>。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.wrap"><code>coroutine.wrap (f)</code></a></h3>

    <p />
    使用主体函数 <code>f</code> 创建一个协程。
    <code>f</code> 必须是一个函数。
    返回一个函数，每次调用它会延续协程。
    传入这个函数的所有参数行为和 <code>resume</code> 的额外参数行为一样。
    函数返回和 <code>resume</code> 一样的返回值，除了第一个布尔值。
    发生错误时，函数关闭该协程并传播错误。

    <p />
    <hr />
    <h3><a name="pdf-coroutine.yield"><code>coroutine.yield (&middot;&middot;&middot;)</code></a></h3>

    <p />
    暂停当前调用的协程的执行。
    传给 <code>yield</code> 的所有参数都作为 <code>resume</code> 的额外返回值。

    <h2>6.3 &ndash; <a name="6.3">模块</a></h2>

    <p />
    包库提供了在 Lua 中加载模块的基本工具。
    它直接在全局环境中导出一个函数：<a href="#pdf-require"><code>require</code></a>。
    其他所有将导出到表 <a name="pdf-package"><code>package</code></a> 中。

    <p />
    <hr />
    <h3><a name="pdf-require"><code>require (modname)</code></a></h3>

    <p />
    加载给定模块。
    函数通过查看 <a href="#pdf-package.loaded"><code>package.loaded</code></a> 表以查明模块 <code>modname</code> 是否已经被加载。
    如果已经加载, <code>require</code> 返回存储在 <code>package.loaded[modname]</code> 中的值。
    (缺省第二个返回值表示调用没有加载模块)
    否则, 它尝试为模块查找一个 <em>loader(加载器)</em>。

    <p />
    要查找一个加载器, <code>require</code> 由表 <a href="#pdf-package.searchers"><code>package.searchers</code></a> 引导。
    这个表中的每个条目都是一个搜索函数，它以特定方式搜索模块。
    通过修改这个表, 我们可以决定 <code>require</code> 查找模块的方式。
    下面解释基于 <a href="#pdf-package.searchers"><code>package.searchers</code></a> 的的默认配置。

    <p />
    首先，<code>require</code> 查询 <code>package.preload[modname]</code>。
    如果它有值，这个值(必须是一个函数)就是加载器。
    否则，<code>require</code> 使用存储在 <a href="#pdf-package.path"><code>package.path</code></a> 中的路径搜索 Lua 加载器。
    如果也没有搜索到, 使用存储在 <a href="#pdf-package.cpath"><code>package.cpath</code></a> 的路径搜索一个 C 加载器。
    如果还失败了, 尝试一个 <em>all-in-one</em> 加载器 (参见 <a href="#pdf-package.searchers"><code>package.searchers</code></a>)。

    <p />
    找到加载器后, <code>require</code> 通过两个参数调用加载器:
    <code>modname</code> 和一个额外值(一个 <em>loader data(加载数据)</em>，也是搜索器返回的)。
    加载数据可以是对模块有用的任意值；对于默认搜索器，他表示找到加载器的位置。
    (例如，如果加载器来自于一个文件，这个额外值就是文件路径)
    如果加载器返回任意的 non-nil(非nil) 值, <code>require</code> 将返回值赋值到 <code>package.loaded[modname]</code>。
    如果加载器没有返回一个 non-nil 值并且没有赋值任何值到 <code>package.loaded[modname]</code>, <code>require</code> 将该条目赋值为 <b>true</b>。
    任何情况下, <code>require</code> 都返回 <code>package.loaded[modname]</code> 的最终值。
    除了该值之外, <code>require</code> 也会也会将搜索器返回的加载数据(指示了 <code>require</code> 找到模块的方式)作为第二个返回值。

    <p />
    如果加载/运行模块时有任何错误，或没有为模块找到任何加载器，<code>require</code> 抛出错误。

    <p />
    <hr />
    <h3><a name="pdf-package.config"><code>package.config</code></a></h3>

    <p />
    一个描述包的编译时配置信息的字符串。
    这个字符串是一个行序列：

    <ul>
        <li>第一行是文件夹分隔字符串。Windows，默认为 '<code>\</code>'， 其他系统为 '<code>/</code>'。</li>
        <li>第二行是分割路径的模板字符。默认为 '<code>;</code>'。</li>
        <li>第三行是标记模板中的替换点字符串。默认为 '<code>?</code>'。</li>
        <li>第四行是在 Windows 中将被替换成可执行程序所在目录的路径的字符串。默认为 '<code>!</code>'。</li>
        <li>第五行是一个记号，该记号之后的所有文本将在构建 <code>luaopen_</code> 函数名时被忽略掉。默认为 '<code>-</code>'。</li>
    </ul>

    <p />
    <hr />
    <h3><a name="pdf-package.cpath"><code>package.cpath</code></a></h3>

    <p />
    <a href="#pdf-require"><code>require</code></a> 搜索 C 加载器时搜索的路径的字符串。

    <p />
    Lua 使用和初始化 Lua 路径 <a href="#pdf-package.path"><code>package.path</code></a> 相同的方式 (使用环境变量 <a name="pdf-LUA_CPATH_5_4"><code>LUA_CPATH_5_4</code></a>,
    或环境变量 <a name="pdf-LUA_CPATH"><code>LUA_CPATH</code></a>, 或定义在 <code>luaconf.h</code> 中的默认路径) 初始化 C 路径 <a href="#pdf-package.cpath"><code>package.cpath</code></a>。

    <p />
    <hr />
    <h3><a name="pdf-package.loaded"><code>package.loaded</code></a></h3>

    <p />
    用于控制 <a href="#pdf-require"><code>require</code></a> 哪个模块已经被加载的表。
    当你请求一个模块 <code>modname</code> 且 <code>package.loaded[modname]</code> 不为 <code>假值</code> 时,
    <a href="#pdf-require"><code>require</code></a> 简单地返回存储在这儿的值。

    <p />
    这个变量只是一个对实际表的引用，对它的赋值都不会影响使用 <code><a href="#pdf-require">require</a></code> 的表。
    实际表存储在 C 注册表 (参见 <a href="#4.3">&sect;4.3</a>) 中, 通过字符串键 <a name="pdf-LUA_LOADED_TABLE"><code>LUA_LOADED_TABLE</code></a> 索引。

    <p />
    <hr />
    <h3><a name="pdf-package.loadlib"><code>package.loadlib (libname, funcname)</code></a></h3>

    <p />
    将主机程序与 C 库 <code>libname</code> 进行动态链接。

    <p />
    如果 <code>funcname</code> 为 "<code>*</code>", 他仅仅是链接该库，将库中的符号都导出给其他动态链接库使用。
    否则, 他查找库中的函数 <code>funcname</code> 并且将函数以 C 函数的形式返回。
    因此, <code>funcname</code> 必须遵循 <a href="#lua_CFunction"><code>lua_CFunction</code></a> 协议
    (参见 <a href="#lua_CFunction"><code>lua_CFunction</code></a>)。

    <p />
    这是一个底层函数。
    它完全绕过了包和模块管理系统。
    和 <a href="#pdf-require"><code>require</code></a> 不一样，他不会进行任何路径搜索，也不会自动添加扩展。
    <code>libname</code> 必须是 C 库的完整文件名，如果需要，还得包含路径和扩展名。
    <code>funcname</code> 必须是 C 库导出的准确名字(取决于使用的 C 编译器和链接器)。

    <p />
    该函数在 ISO C 中并不支持。
    因此，它只在部分平台有效 (Windows ，Linux ，Mac OS X, Solaris, BSD, 加上支持 <code>dlfcn</code> 标准的 Unix 系统)。

    <p />
    函数本质上是不安全的，因为他允许 Lua 调用系统中任何可读动态库中的任何函数。
    (Lua 调用任何函数都假定函数有适当的原型并且遵循一个适当的协议
    (参见 <a href="#lua_CFunction"><code>lua_CFunction</code></a>)。
    因此, 调用任意动态库中的任意函数往往会导致访问冲突)

    <p />
    <hr />
    <h3><a name="pdf-package.path"><code>package.path</code></a></h3>

    <p />
    <a href="#pdf-require"><code>require</code></a> 用以搜索 Lua 加载器的路径字符串。

    <p />
    在启动时，Lua使用环境变量 <a name="pdf-LUA_PATH_5_4"><code>LUA_PATH_5_4</code></a>
    或 <a name="pdf-LUA_PATH"><code>LUA_PATH</code></a> 的值初始化此变量，
    如果这些环境变量未定义，则使用在 <code>luaconf.h</code> 中定义的默认路径。
    在环境变量的值中，"<code>;;</code>"将被默认路径替换。

    <p />
    <hr />
    <h3><a name="pdf-package.preload"><code>package.preload</code></a></h3>

    <p />
    一个存储指定模块的加载器的表。 (参见 <a href="#pdf-require"><code>require</code></a>)。

    <p />
    这个变量只是一个对实际表的引用，对它的赋值都不会影响使用 <code><a href="#pdf-require">require</a></code> 的表。
    实际表存储在 C 注册表 (参见 <a href="#4.3">&sect;4.3</a>) 中, 通过字符串键 <a
        name="pdf-LUA_PRELOAD_TABLE"><code>LUA_PRELOAD_TABLE</code></a> 索引。

    <p />
    <hr />
    <h3><a name="pdf-package.searchers"><code>package.searchers</code></a></h3>

    <p />
    用于控制 <a href="#pdf-require"><code>require</code></a> 查找模块方式的表。

    <p />
    表中的每个条目都是一个 <em>searcher function(搜索器函数)</em>。
    当查找一个模块时， <a href="#pdf-require"><code>require</code></a> 将模块名(传给 <a href="#pdf-require"><code>require</code></a>
    的参数) 作为它的唯一参数按升序调用每个搜索器。
    如果搜索器找到了模块, 它返回另一个函数(模块 <em>loader(加载器)</em>),
    加上一个加载数据(一个 <em>loader data(加载数据)</em>, 它将被作为参数传入加载器并作为 <a href="#pdf-require"><code>require</code></a> 的第二个返回值)。
    如果不能找到模块, 它返回一个解释原因的字符串(或如果没有什么好说的则为 <b>nil</b>)。

    <p />
    Lua 使用四个加载器函数初始化这个表。

    <p />
    第一个搜索器简单地查找 <a href="#pdf-package.preload"><code>package.preload</code></a> 表中的加载器。

    <p />
    第二个搜索器将加载器作为一个 Lua 库，使用存储在 <a href="#pdf-package.path"><code>package.path</code></a> 中的路径来搜索。
    搜索过程与函数 <a href="#pdf-package.searchpath"><code>package.searchpath</code></a> 中描述的一样。

    <p />
    第三个搜索器将加载器作为一个 C 库，使用变量 <a href="#pdf-package.cpath"><code>package.cpath</code></a> 中的路径来搜索。
    一样的，搜索过程与函数 <a href="#pdf-package.searchpath"><code>package.searchpath</code></a> 中描述的一样。
    例如，如果 C 路径是字符串

    <pre>
     "./?.so;./?.dll;/usr/local/?/init.so"
</pre>
    <p />
    模块搜索器 <code>foo</code> 将按顺序尝试打开文件 <code>./foo.so</code>, <code>./foo.dll</code>, 和
    <code>/usr/local/foo/init.so</code>。
    当它找到一个 C 库时，搜索器首先使用一个动态链接工具去将库与应用程序进行链接。
    然后它尝试在库中找到一个 C 函数作为加载器。
    该 C 函数的名字是字符串 "<code>luaopen_</code>" 与模块名的副本的连接，其中模块的每个点替换为下划线。
    此外，如果模块名中有连字符(<code>'-'</code>)，连接符及其之后的字符将被移除。
    例如，如果模块名为 <code>a.b.c-v2.1</code>，函数名将为 <code>luaopen_a_b_c</code>。

    <p />
    第四个搜索器尝试一个 <em>all-in-one loader(一体化加载器)</em>.
    它在 C 路径中搜索给定模块的根名称的库。
    例如, 当请求 <code>a.b.c</code> 时, 它将搜索 C 库 <code>a</code>.
    如果找到了，它会在其中查找子模块的打开函数；
    在我们的例子中, 它将是 <code>luaopen_a_b_c</code>。
    通过此功能, 一个包可以将多个 C 子模块打包到一个单独的库中。
    每个子模块保留其原始打开函数。

    <p />
    除了第一个搜索器(预加载)之外，所有搜索器返回的额外值都是模块所在的文件路径，返回方式与 <a href="#pdf-package.searchpath"><code>package.searchpath</code></a>
    相同。
    第一个搜索器总是返回字符串 "<code>:preload:</code>"。

    <p />
    搜索器不应该抛出错误并且在 Lua 中没有副作用(他们可能在 C 中有副作用，例如将应用与库连接)。

    <p />
    <hr />
    <h3><a name="pdf-package.searchpath"><code>package.searchpath (name, path [, sep [, rep]])</code></a>
    </h3>

    <p />
    在给定路径 <code>path</code> 中搜索给定 <code>name</code>。

    <p />
    路径是一个包含以分号分割的 <em>templates(模板)</em> 字符串序列。
    对于每个模板，该函数用 <code>name</code> 的副本替换模板中的每个问号(如果有)，
    其中所有的 <code>sep</code>(默认为点) 将被替换为 <code>rep</code>(默认为系统目录分隔符)，
    然后尝试打开生成的文件名。

    <p />
    例如，如果路径是字符串

    <pre>
     "./?.Lua ;./?.lc;/usr/local/?/init.Lua "
</pre>
    <p />
    搜索名字 <code>foo.a</code> 将依次尝试打开文件 <code>./foo/a.Lua </code>, <code>./foo/a.lc</code>, 和
    <code>/usr/local/foo/a/init.Lua </code>。

    <p />
    返回能使用读取模式(之后将关闭文件)打开的第一个文件的名字, 或都没有成功时返回 <b>fail</b> 加上一个错误消息(错误消息列出所有尝试打开的文件名)。

    <h2>6.4 &ndash; <a name="6.4">字符串操作</a></h2>

    <p />
    这个库提供了字符串操作的常用操作，例如查找子串，匹配模式等。
    在 Lua 中索引一个字符串时，第一个字符的位置是 1(而不是 0，如 C 中)。
    允许索引为负，并将其解释为从字符串末尾开始向前的索引。
    因此，最后一个字符的位置是 -1，以此类推。

    <p />
    字符串库在表 <a name="pdf-string"><code>string</code></a> 中提供所有函数。
    他还为字符串设置了 <code>__index</code> 字段指向 <code>string</code> 表的元表。
    因此，你可以用面向对象的风格使用字符串函数。
    例如, <code>string.byte(s,i)</code> 可以写成 <code>s:byte(i)</code>。

    <p />
    字符串库采用单字节字符编码。

    <p />
    <hr />
    <h3><a name="pdf-string.byte"><code>string.byte (s [, i [, j]])</code></a></h3>
    返回字符 <code>s[i]</code>, <code>s[i+1]</code>, ..., <code>s[j]</code> 的内部数字代码。
    <code>i</code> 的默认值为 1。
    <code>j</code> 的默认值为 <code>i</code>。
    这些索引会根据和函数 <a href="#pdf-string.sub"><code>string.sub</code></a> 一样的规则进行修正。

    <p />
    数字代码不一定跨平台可移植。

    <p />
    <hr />
    <h3><a name="pdf-string.char"><code>string.char (&middot;&middot;&middot;)</code></a></h3>
    接收零个或多个整数。返回一个与参数个数相同长度的字符串，其中每个字符的内部数字代码等于其相应的参数。

    <p />
    数字代码不一定跨平台可移植。

    <p />
    <hr />
    <h3><a name="pdf-string.dump"><code>string.dump (function [, strip])</code></a></h3>

    <p />
    返回一个包含给定函数的二进制表示(一个二进制块)的字符串。
    因此在之后 <a href="#pdf-load"><code>load</code></a> 这个字符串将返回该函数的副本(但是使用新的上值)。
    如果 <code>strip</code> 是一个真值, 该二进制表示可能不会包含与函数相关的调试信息，以节省空间。

    <p />
    带上值的函数只保存上值的数目。
    当重新加载时，这些上值接收新的示例。
    (参见 <a href="#pdf-load"><code>load</code></a> 函数以了解这些上值初始化的相关细节。 你可以使用调试库以适当的方式地序列化和重新加载带上值的函数)

    <p />
    <hr />
    <h3><a name="pdf-string.find"><code>string.find (s, pattern [, init [, plain]])</code></a></h3>

    <p />
    在字符串 <code>s</code> 中搜索 <code>pattern</code> (参见 <a href="#6.4.1">&sect;6.4.1</a>) 的第一次匹配。
    如果找到， <code>find</code> 返回它们在 <code>s</code> 中的起始和结束位置的索引。
    否则返回 <b>fail</b>。
    第三个可选参数 <code>init</code> 指定搜索从哪里开始，默认值为 1，并且可以为负数。
    如果第四个可选参数 <code>plain</code> 为 <code>true</code>，关闭匹配模式，此时函数只做简单的"查找子串"操作，而 <code>pattern</code> 中没有字符被看做魔法字符。

    <p />
    如果匹配模式中有捕获组，则在成功的匹配中，捕获的值也会返回，位于两个索引之后。

    <p />
    <hr />
    <h3><a name="pdf-string.format"><code>string.format (formatstring, &middot;&middot;&middot;)</code></a>
    </h3>

    <p />
    返回其变参列表的格式化版本，参数列表由第一个参数(必须是字符串)描述的说明。 格式化字符串遵循与 ISO C 函数 <code>sprintf</code> 相同的规则。
    唯一的不同是不支持转换修饰符和说明符 <code>F</code>, <code>n</code>, <code>*</code>, <code>h</code>, <code>L</code>, <code>l</code>，并且有一个额外的说明符 <code>q</code>。

    <p />
    说明符 <code>q</code> 格式化布尔值, nil, 数字和字符串以便结果在 Lua 源码中为一个有效常量。
    布尔值和 nil 被写作显而易见的形式(<code>true</code>, <code>false</code>, <code>nil</code>)。
    浮点数以十六进制写入，以保存完整精度。
    字符串写入双引号之间，必要时使用转义序列，以确保 Lua 解释器可以安全地回读它。
    例如，调用

    <pre>
     string.format('%q', 'a string with "quotes" and \n new line')
</pre>
    <p />
    将产生字符串:

    <pre>
     "a string with \"quotes\" and \
      new line"
</pre>
    <p />
    该说明符不支持修饰符 (标识、宽度、精度)。

    <p />
    转换说明符 <code>A</code>, <code>a</code>, <code>E</code>, <code>e</code>, <code>f</code>, <code>G</code> 和 <code>g</code> 都期望一个数字作为参数。
    说明符 <code>c</code>, <code>d</code>, <code>i</code>, <code>o</code>, <code>u</code>, <code>X</code> 和 <code>x</code> 期望一个整数。
    当 Lua 使用 C89 编译时, 说明符 <code>A</code> 和 <code>a</code> (十六进制浮点数) 不支持修饰符。

    <p />
    说明符 <code>s</code> 期望一个字符串。
    如果参数不是一个字符串，他将该值通过与 <a href="#pdf-tostring"><code>tostring</code></a> 一样的规则进行转换。
    如果说明符有修饰符，对应的字符串不应该包含嵌入零。

    <p />
    说明符 <code>p</code> 使用 <a href="#lua_topointer"><code>lua_topointer</code></a> 格式化指针以返回。
    它为表, 用户数据, 线程, 字符串和函数给出唯一字符串标识。
    对于其他值 (数字, nil, 布尔值), 该说明符结果为一个表示指针 <code>NULL</code> 的字符串。

    <p />
    <hr />
    <h3><a name="pdf-string.gmatch"><code>string.gmatch (s, pattern [, init])</code></a></h3>
    返回一个迭代器，每当调用这个迭代器时，返回 <code>pattern(匹配模式)</code>(参见 <a href="#6.4.1">&sect;6.4.1</a>) 在字符串 <code>s</code> 中的下一个捕获，
    如果 <code>pattern</code> 没有捕获，则在每次调用中生成整个匹配。
    第三个可选参数 <code>init</code> 指定搜索从哪里开始，默认值为 1，并且可以为负数。

    <p />
    作为示例, 下面循环将迭代字符串 <code>s</code> 中的所有单词, 每行打印一个:

    <pre>
     s = "hello world from Lua "
     for w in string.gmatch(s, "%a+") do
       print(w)
     end
</pre>
    <p />
    下一个示例从给定字符串收集所有键值对 <code>key=value</code> 放入表中：

    <pre>
     t = {}
     s = "from=world, to=Lua "
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end
</pre>

    <p />
    对于这个函数，位于匹配模式开头的 '<code>^</code>' 不会起到定位作用，因为这会阻止迭代。

    <p />
    <hr />
    <h3><a name="pdf-string.gsub"><code>string.gsub (s, pattern, repl [, n])</code></a></h3>
    返回一个 <code>s</code> 的副本，其中所有 (如果给定了 <code>n</code> 则为前 <code>n</code> 个)
    <code>pattern</code> (参见 <a href="#6.4.1">&sect;6.4.1</a>) 都被替换为字符串 <code>repl</code>，
    <code>repl</code> 可以是一个字符串，一个表或一个函数。
    <code>gsub</code> 还返回总匹配次数作为第二个返回值。
    <code>gsub</code> 的名字来自于 <em>Global SUBstitution</em>。

    <p />
    如果 <code>repl</code> 是一个字符串，那么他的值用于替换。
    字符 <code>%</code> 作为一个转义字符: <code>repl</code> 中 <code>%<em>d</em></code>(<em>d</em> 区间为[1, 9]) 形式的序列, 表示第 <em>d</em> 个捕获的子串。
    序列 <code>%0</code> 表示整个匹配;
    序列 <code>%%</code> 表示一个单独的 <code>%</code>。

    <p />
    如果 <code>repl</code> 是一个表, 将第一个捕获作为键在表中查找所有匹配。

    <p />
    如果 <code>repl</code> 是一个函数, 每次出现匹配时将所有捕获的子串依次作为参数调用这个函数。

    <p />
    任何情况下，没有设定捕获的模板都看成是捕获整个模板。

    <p />
    如果表中查询或函数调用的结果是一个字符串或数字，其作为替换字符串。
    否则，如果是一个 <b>false</b> 或 <b>nil</b>，则不会进行替换(即，保留字符串中的原始串)。

    <p />
    下面是一些例子:

    <pre>
     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --&gt; x="hello hello world world"

     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --&gt; x="hello hello world"

     x = string.gsub("hello world from Lua ", "(%w+)%s*(%w+)", "%2 %1")
     --&gt; x="world hello Lua from"

     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --&gt; x="home = /home/roberto, user = roberto"

     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return load(s)()
         end)
     --&gt; x="4+5 = 9"

     local t = {name="Lua ", version="5.4"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --&gt; x="Lua -5.4.tar.gz"
</pre>

    <p />
    <hr />
    <h3><a name="pdf-string.len"><code>string.len (s)</code></a></h3>

    <p />
    接收一个字符串并返回它的长度。
    空字符串 <code>""</code> 长度为 0。
    嵌入零也会被计数, 因此 <code>"a\000bc\000"</code> 长度为5。

    <p />
    <hr />
    <h3><a name="pdf-string.lower"><code>string.lower (s)</code></a></h3>

    <p />
    接收一个字符串并返回该字符串中所有大写字母转换为小写的副本。
    所有其他字符保持不变。
    大写字母的定义取决于当前的区域设置。

    <p />
    <hr />
    <h3><a name="pdf-string.match"><code>string.match (s, pattern [, init])</code></a></h3>

    <p />
    在字符串 <code>s</code> 中查找 <code>pattern</code> (参见 <a href="#6.4.1">&sect;6.4.1</a>) 的第一个 <em>match(匹配)</em>。
    如果找到了, <code>match</code> 返回匹配模式的捕获；否则返回 <b>fail</b>。
    如果 <code>pattern</code> 没有指定捕获，返回整个匹配。
    第三个可选参数 <code>init</code> 指定搜索从哪里开始，默认值为 1，并且可以为负数。

    <p />
    <hr />
    <h3><a name="pdf-string.pack"><code>string.pack (fmt, v1, v2, &middot;&middot;&middot;)</code></a></h3>

    <p />
    返回一个打包了(即以二进制形式序列化) v1, v2 等值的二进制字符串。 字符串 fmt 为打包格式(参见 <a href="#6.4.2">&sect;6.4.2</a>)。

    <p />
    <hr />
    <h3><a name="pdf-string.packsize"><code>string.packsize (fmt)</code></a></h3>

    <p />
    返回以给定格式从 <a href="#pdf-string.pack"><code>string.pack</code></a> 打包的字符串的长度。
    格式字符串不能有可变长度选项 '<code>s</code>' 或 '<code>z</code>' (参见 <a href="#6.4.2">&sect;6.4.2</a>)。

    <p />
    <hr />
    <h3><a name="pdf-string.rep"><code>string.rep (s, n [, sep])</code></a></h3>

    <p />
    返回一个以字符串 <code>sep</code> 为分隔符的 <code>n</code> 个字符串 <code>s</code> 的连接字符串。
    <code>sep</code> 默认值为空字符串(即没有分隔符)。
    如果 <code>n</code> 不是整数则返回空字符串。

    <p />
    (注意，调用这个函数时，如果 <code>n</code> 很大的话很容易耗尽机器的内存)

    <p />
    <hr />
    <h3><a name="pdf-string.reverse"><code>string.reverse (s)</code></a></h3>

    <p />
    返回将字符串 <code>s</code> 反转的字符串。

    <p />
    <hr />
    <h3><a name="pdf-string.sub"><code>string.sub (s, i [, j])</code></a></h3>

    <p />
    返回 <code>s</code> 从 <code>i</code> 开始至 <code>j</code> 处的子串; <code>i</code> 和 <code>j</code> 都可以是负数。
    如果 <code>j</code> 缺省, 假定为 -1(表示字符串长度)。
    特别地, 调用 <code>string.sub(s,1,j)</code> 返回 <code>s</code> 长度 <code>j</code> 的前缀，
    <code>string.sub(s, -i)</code> (正数 <code>i</code>) 返回 <code>s</code> 长度 <code>i</code> 的后缀。

    <p />
    如果转换后的负指数 <code>i</code> 小于 1, 将它纠正为 1。
    如果 <code>j</code> 大于字符串长度, 纠正为字符串长度。
    如果在修正之后, <code>i</code> 大于 <code>j</code> 函数返回空字符串。

    <p />
    <hr />
    <h3><a name="pdf-string.unpack"><code>string.unpack (fmt, s [, pos])</code></a></h3>

    <p />
    返回已经根据字符串格式 <code>fmt</code> (参见 <a href="#6.4.2">&sect;6.4.2</a>) 打包的
    字符串 <code>s</code> (参见 <a href="#pdf-string.pack"><code>string.pack</code></a>) 的值。
    可选的 <code>pos</code> 标记从字符串 <code>s</code> 的什么位置开始读取 (默认为 1)。
    读取值后，函数还会返回 <code>s</code> 中第一个未读取字节的位置。

    <p />
    <hr />
    <h3><a name="pdf-string.upper"><code>string.upper (s)</code></a></h3>

    <p />
    接收一个字符串并返回该字符串中所有小写字母转换为大写的副本。
    其他字符不会修改
    对小写字符的定义取决于当前的区域设置。

    <h3>6.4.1 &ndash; <a name="6.4.1">匹配模式</a></h3>

    <p />
    Lua 中的匹配模式用正则字符串描述，用于模式匹配函数
    <a href="#pdf-string.find"><code>string.find</code></a>,
    <a href="#pdf-string.gmatch"><code>string.gmatch</code></a>,
    <a href="#pdf-string.gsub"><code>string.gsub</code></a>
    和 <a href="#pdf-string.match"><code>string.match</code></a>。
    这一节描述这些字符串的语法和含义(即他们会匹配什么)
    该部分描述了这些字符串的语法和含义(即它们匹配的内容)。

    <h4>字符类:</h4>
    <p />
    一个 <em>character class(字符类)</em> 用于表示一类字符。
    以下组合可用于描述字符类：

    <ul>
        <li><b><em>x</em>: </b>
            (<em>x</em> 不能是 <em>magic characters(魔法字符)</em> <code>^$()%.[]*+-?</code> 中的)
            表示字符串 <em>x</em> 自身。
        </li>

        <li><b><code>.</code>: </b> (一个点) 表示任何字符。</li>
        <li><b><code>%a</code>: </b> 表示一个字母。</li>
        <li><b><code>%c</code>: </b> 表示一个控制字符。</li>
        <li><b><code>%d</code>: </b> 表示一个数字。</li>
        <li><b><code>%g</code>: </b> 表示一个除空白符外的可打印字符。</li>
        <li><b><code>%l</code>: </b> 表示一个小写字母。</li>
        <li><b><code>%p</code>: </b> 表示一个标点符号。</li>
        <li><b><code>%s</code>: </b> 表示一个空白字符。</li>
        <li><b><code>%u</code>: </b> 表示一个大写字母。</li>
        <li><b><code>%w</code>: </b> 表示一个字母和数字。</li>
        <li><b><code>%x</code>: </b> 表示一个十六进制数字。</li>
        <li><b><code>%<em>x</em></code>: </b> (这里的 <em>x</em> 是任意非字母或数字的字符)
            表示字符 <em>x</em>。
            这是对魔法字符转义的标准方式。
            所有非字母或数字的字符(包括所有标点，也包括非魔法字符)都可以用前置一个 '<code>%</code>' 放在模式串中表示自身。
        </li>

        <li><b><code>[<em>set</em>]</code>: </b>
            表示一个由 <em>set</em> 中所有字符组成的集合的类别。
            用 <code>-</code> 将范围的结束字符按升序分隔可以指定一个字符范围。
            上面描述的所有类 <code>%</code><em>x</em> 也可以用作 <em>set</em> 中的组件。
            <em>set</em> 中的所有其他字符都表示他们自身。
            例如， <code>[%w_]</code> (或 <code>[_%w]</code>) 表示任何字母和数字加上下划线, <code>[0-7]</code> 表示一个八进制数字,
            <code>[0-7%l%-]</code> 表示一个八进制数字加上小写字母与 '<code>-</code>' 字符。

            <p />
            可以在将一个右方括号('<code>]</code>')放在第一个字符以把它加入到集合中。
            可以将连字符('<code>-</code>')放在第一个或最后一个字符以把它加入集合中。
            (对于这两种情况，都可以使用转义符)

            <p />
            范围和类之间的相互作用未定义。
            因此，像 <code>[%a-z]</code> 和 <code>[a-%%]</code> 这样的匹配模式都没有意义。
        </li>

        <li><b><code>[^<em>set</em>]</code>: </b>
            表示 <em>set</em> 的补集, <em>set</em> 如上所述。
        </li>
    </ul>
    <p />
    对于由单个字符表示的任何类 (<code>%a</code>, <code>%c</code> 等)，相应的大写字母表示对应类的补集。
    例如, <code>%S</code> 表示非空白字符。

    <p />
    字母，空白符和其他字符组的定义依赖当前区域设置。
    特别地，类 <code>[a-z]</code> 可能不等价于 <code>%l</code>。

    <h4>模式条目:</h4>
    <p />
    一个 <em>pattern item(条目)</em> 可以是

    <ul>
        <li>一个字符类，该字符类匹配任何该字符中的类； </li>
        <li>
            一个字符类后跟一个 '<code>*</code>'，将匹配类中零个或多个该类的字符。
            这个条目总是匹配尽可能长的串。
        </li>

        <li>
            一个字符类后跟一个 '<code>+</code>', 将匹配一个或多个该类的字符。
            这个条目总是匹配尽可能长的串。
        </li>

        <li>
            一个字符类后跟一个 '<code>-</code>', 将匹配类中零个或多个该类的字符。
            与 '<code>*</code>' 不同的是，这个条目总是匹配尽可能短的串。
        </li>

        <li>
            一个字符类后跟一个 '<code>?</code>', 将匹配零个或一个该类的字符。
            如果可能，它会匹配一个。
        </li>

        <li>
            <code>%<em>n</em></code>, 这里的 <em>n</em> 在 1 到 9 之间;
            这个条目与第 <em>n</em> 个捕获的字符串相等的子字符串匹配
            (见下方);
        </li>

        <li>
            <code>%b<em>xy</em></code>, 这儿的 <em>x</em> 和 <em>y</em> 是两个不同的字符；
            这个条目字符串从 <em>x</em> 开始，<em>y</em> 结束，其中 <em>x</em> 和 <em>y</em> 是 <em>balanced(平衡的)</em>。
            这意味着, 如果从左往右读取字符串，对于 <em>x</em> 计数 <em>+1</em> 对于 <em>y</em> 计数 <em>-1</em>,
            结束 <em>y</em> 是计数达到 0 的第一个 <em>y</em>。
            例如, 项 <code>%b()</code> 匹配带有圆括号的表达式。
        </li>

        <li>
            <code>%f[<em>set</em>]</code>, a <em>frontier pattern(边境模式；)</em>;
            这个条目会匹配到一个位于 <em>set</em> 内某个字符之前的一个空串，且这个位置的前一个字符不属于 <em>set</em>。
            集合 <em>set</em> 的含义如前面所述。 匹配出的那个空串之开始和结束点的计算就看成该处有个字符 '\0' 一样。
        </li>
    </ul>

    <h4>模式:</h4>
    <p />
    <em>pattern(模式)</em> 是匹配条目的序列。
    在匹配模式的开始处的 '<code>^</code>' 将锚定从字符串开始处匹配。
    在匹配模式的末尾处的 '<code>$</code>' 将锚定从字符串结尾处匹配。
    在其他位置, '<code>^</code>' 和 '<code>$</code>' 没有特殊含义，并且表示他们自身。

    <h4>捕获:</h4>
    <p />
    匹配模式可以包含用括号括起来的子模式。
    他们表示 <em>captures(捕获)</em>。
    当一个匹配成功，主字符串中与捕获的子串将被保存(<em>captured</em>)，以供以后使用。
    捕获根据他们的左圆括号进行编号。
    例如，在匹配模式 <code>"(a*(.)%w(%s*))"</code> 中，与 <code>"a*(.)%w(%s*)"</code> 匹配的字符串保存在第一个捕获中，因此编号为 1，
    与 "<code>.</code>" 匹配的字符串捕获编号为 2， 与 "<code>%s*</code>" 匹配的字符串捕获编号为 3。

    <p />
    有一种特殊情况, 捕获 <code>()</code> 捕获当前字符串位置(一个数字)。
    例如, 如果我们在字符串 <code>"flaaap"</code> 中使用匹配模式 <code>"()aa()"</code>， 他将有两个捕获：3 和 5。

    <h4>多重匹配:</h4>
    <p />
    函数 <a href="#pdf-string.gsub"><code>string.gsub</code></a> 和迭代器 <a
        href="#pdf-string.gmatch"><code>string.gmatch</code></a> 在主体字符串中匹配给定模式的多个出现。
    对于这些函数, 只有前一个匹配的末尾之后至少一个字节结束时，才将新匹配视为有效。
    换句话说，匹配模式将紧接着另一个匹配之后的空字符串作为一个匹配。
    作为示例，考虑下面代码的结果。

    <pre>
     &gt; string.gsub("abc", "()a*()", print);
     --&gt; 1   2
     --&gt; 3   3
     --&gt; 4   4
</pre>
    <p />
    第二个和第三个结果来自 Lua 在 '<code>b</code>' 和 '<code>c</code>' 之后匹配的空串。
    Lua 不会匹配 '<code>a</code>' 后的空串, 因为它的结束位置和前一匹配的相同。

    <h3>6.4.2 &ndash; <a name="6.4.2">格式字符串的打包和解包</a></h3>

    <p />
    函数 <a href="#pdf-string.pack"><code>string.pack</code></a>,
    <a href="#pdf-string.packsize"><code>string.packsize</code></a> 和 <a
        href="#pdf-string.unpack"><code>string.unpack</code></a>
    的第一个参数是一个格式字符串，它描述了创建或读取的结构的布局。

    <p />
    格式串是一个转换选项的序列，转换选项如下：

    <ul>
        <li><b><code>&lt;</code>: </b>设为小端编码</li>
        <li><b><code>&gt;</code>: </b>设为大端编码</li>
        <li><b><code>=</code>: </b>大小端遵循本地设置</li>
        <li><b><code>![<em>n</em>]</code>: </b>设置最大对齐数为 <code>n</code>(默认遵循本地对齐设置)</li>
        <li><b><code>b</code>: </b>一个有符号字节(<code>char</code>)</li>
        <li><b><code>B</code>: </b>一个无符号字节 (<code>char</code>)</li>
        <li><b><code>h</code>: </b>一个有符号 <code>short</code> (本地大小)</li>
        <li><b><code>H</code>: </b>一个无符号 <code>short</code> (本地大小)</li>
        <li><b><code>l</code>: </b>一个有符号 <code>long</code> (本地大小)</li>
        <li><b><code>L</code>: </b>一个无符号 <code>long</code> (本地大小)</li>
        <li><b><code>j</code>: </b>一个 <code>lua_Integer</code></li>
        <li><b><code>J</code>: </b>一个 <code>lua_Unsigned</code></li>
        <li><b><code>T</code>: </b>一个 <code>size_t</code> (本地大小)</li>
        <li><b><code>i[<em>n</em>]</code>: </b>一个<code>n</code> 字节(默认为本地大小)的有符号 <code>int</code></li>
        <li><b><code>I[<em>n</em>]</code>: </b>一个<code>n</code> 字节(默认为本地大小)的无符号 <code>int</code></li>
        <li><b><code>f</code>: </b>一个 <code>float</code> (本地大小)</li>
        <li><b><code>d</code>: </b>一个 <code>double</code> (本地大小)</li>
        <li><b><code>n</code>: </b>一个 <code>lua_Number</code></li>
        <li><b><code>c<em>n</em></code>: </b>一个 <code>n</code> 字节的字符串</li>
        <li><b><code>z</code>: </b>一个零结尾字符串</li>
        <li><b><code>s[<em>n</em>]</code>: </b>一个由其长度(使用 <code>n</code> 字节进行编码，默认为 <code>size_t</code>)开头的字符串</li>
        <li><b><code>x</code>: </b>一个字节的填充</li>
        <li><b><code>X<em>op</em></code>: </b>根据选项 <code>op</code>(忽略它的其他方面)对齐的一个空条目</li>
        <li><b>'<code> </code>': </b>(空格)忽略</li>
    </ul>
    <p />
    ("<code>[<em>n</em>]</code>" 表示一个可选整数)
    除填充、空格和配置项(选项 "<code>xX &lt;=&gt;!</code>")外,
    每个选项都对应 <a href="#pdf-string.pack"><code>string.pack</code></a> 中的一个参数
    或 <a href="#pdf-string.unpack"><code>string.unpack</code></a> 中的一个返回值。

    <p />
    对于选项 "<code>!<em>n</em></code>", "<code>s<em>n</em></code>", "<code>i<em>n</em></code>" 和
    "<code>I<em>n</em></code>", <code>n</code> 可以是 1 至 16 之间的整数。
    所有整数选项都会做溢出检查;
    <a href="#pdf-string.pack"><code>string.pack</code></a> 检测给定的值是否适合给定的大小；
    <a href="#pdf-string.unpack"><code>string.unpack</code></a> 检测读取的值是否适合 Lua 整数。
    对于无符号选项，Lua 整数也被视为无符号值。

    <p />
    所有格式字符串都以 "<code>!1=</code>" 为前缀,也就是说, 最大对齐为 1(不对齐) 并使用本地端序。

    <p />
    本地端序假定整个系统是大端序或小端序。
    打包函数不能正确模拟混合端序格式的行为。

    <p />
    对齐按如下规则工作:
    对于每个选项, 格式填充额外的字节直到数据从一个偏移开始(这个位置是该选项的大小和最大对齐数中较小的那个数的倍数);
    这个最小值必须是2的整数次方。
    选项 "<code>c</code>" 和 "<code>z</code>" 不会对齐;
    选项 "<code>s</code>" 根据他开头的整数对齐。

    <p />
    所有的填充在 <a href="#pdf-string.pack"><code>string.pack</code></a> 中用 0 填充并且在 <a
        href="#pdf-string.unpack"><code>string.unpack</code></a> 中被忽略。

    <h2>6.5 &ndash; <a name="6.5">UTF-8 支持</a></h2>

    <p />
    这个库提供 UTF-8 编码的基础支持。
    所有函数在表 <a name="pdf-utf8"><code>utf8</code></a> 中提供。
    此库不提供除编码处理之外的任何 Unicode 支持。
    所有需要了解字符含义的操作，比如字符分类，都不在此范畴。

    <p />
    除非另有说明, 所有期望一个字节位置作为参数的函数假定给定位置为字节序列的起始位置或主体字符串的长度加 1；
    与字符串库一样，负数索引从字符串的末尾开始计数。

    <p />
    创建字节序列的函数接受原始 UTF-8 规范定义的所有值，即最大值为 <code>0x7FFFFFFF</code>；这意味着字节序列最多可达 6 个字节。

    <p />
    解释字节序列的函数值接受有效序列(格式良好并且不会超长)。
    默认, 他们只接收产生有效 Unicode 码点的字节序列，拒绝大于 <code>10FFFF</code> 的值和代替值。
    布尔参数 <code>lax</code> 在可用时，解除这些检查，以便接受 <code>0x7FFFFFFF</code> 以内的所有值(格式不佳或序列过长时将被拒绝)。

    <p />
    <hr />
    <h3><a name="pdf-utf8.char"><code>utf8.char (&middot;&middot;&middot;)</code></a></h3>

    <p />
    接收零或多个整数， 将每个整数转换成对应的 UTF-8 字节序列，并返回这些序列连接到一起的字符串。

    <p />
    <hr />
    <h3><a name="pdf-utf8.charpattern"><code>utf8.charpattern</code></a></h3>

    <p />
    用于精确匹配一个 UTF-8 字节序列的模板 (一个字符串, 不是函数) "<code>[\0-\x7F\xC2-\xFD][\x80-\xBF]*</code>"
    (参见 <a href="#6.4.1">&sect;6.4.1</a>), 它假定对象是一个有效 UTF-8 字符串。

    <p />
    <hr />
    <h3><a name="pdf-utf8.codes"><code>utf8.codes (s [, lax])</code></a></h3>

    <p />
    返回迭代器，恒定值和初始化状态，因此

    <pre>
     for p, c in utf8.codes(s) do <em>body</em> end
</pre>
    <p />
    将迭代字符串 <code>s</code> 中的所有 UTF-8 字符，
    其中 <code>p</code> 是位置 (按字节数)， <code>c</code> 是每个字符的码点。
    遇到无效字节序列将抛出错误。

    <p />
    <hr />
    <h3><a name="pdf-utf8.codepoint"><code>utf8.codepoint (s [, i [, j [, lax]]])</code></a></h3>

    <p />
    返回 <code>s</code> 中所有字节位置 <code>i</code> 和 <code>j</code>(都包含)之间字符的码点(整数)。
    <code>i</code> 默认为 1， <code>j</code> 默认为 <code>i</code>。
    遇到无效字节序列将抛出错误。

    <p />
    <hr />
    <h3><a name="pdf-utf8.len"><code>utf8.len (s [, i [, j [, lax]]])</code></a></h3>

    <p />
    返回字符串 <code>s</code> 位置 <code>i</code> 和 <code>j</code>(都包含)之间的 UTF-8 字符的个数。
    <code>i</code> 默认为 1， <code>j</code> 默认为 -1。
    如果找到无效字节序列，返回 <b>fail</b> 加上第一个无效字节的位置。

    <p />
    <hr />
    <h3><a name="pdf-utf8.offset"><code>utf8.offset (s, n [, i])</code></a></h3>

    <p />
    返回字符串 <code>s</code> 中从 <code>i</code> 开始计数的第 <code>n</code> 个字符的编码位置(按字节)。
    一个负数 <code>n</code> 获取从 <code>i</code> 开始获取前面的字符。
    当 <code>n</code> 不为负数时，<code>i</code> 默认为 1，否则，默认为 <code>#s + 1</code>, 因此 <code>utf8.offset(s, -n)</code>
    获取从字符串结尾开始计数的第 <code>n</code> 个字符。
    如果指定字符即不在指定主体字符串中，也不在指定字符之后，则返回 <code>fail</code>。

    <p />
    作为特例, 当 <code>n</code> 为 0 时，函数返回包含字符串 <code>s</code> 的第 <code>i</code> 个字节字符的编码起点。

    <p />
    函数假定 <code>s</code> 是一个有效 UTF-8 字符串。

    <h2>6.6 &ndash; <a name="6.6">表操作库</a></h2>

    <p />
    这个库提供了操作表的常用函数。
    他的所有函数都在表 <a name="pdf-table"><code>table</code></a> 中提供。

    <p />
    记住，只要一个操作需要表的长度，所有关于长度操作符的注意事项都适用 (参见 <a href="#3.4.7">&sect;3.4.7</a>)。
    所有函数忽略作为参数表中的非数字键。

    <p />
    <hr />
    <h3><a name="pdf-table.concat"><code>table.concat (list [, sep [, i [, j]]])</code></a></h3>

    <p />
    给定一个所有元素都是字符串或数字的列表，返回字符串 <code>list[i]..sep..list[i+1] &middot;&middot;&middot; sep..list[j]</code>。
    <code>sep</code> 默认为空串, <code>i</code> 默认为 1， <code>j</code> 默认为 <code>#list</code>。
    如果 <code>i</code> 大于 <code>j</code>, 返回空串。

    <p />
    <hr />
    <h3><a name="pdf-table.insert"><code>table.insert (list, [pos,] value)</code></a></h3>

    <p />
    在 <code>list</code> 的 <code>pos</code> 位置插入元素 <code>value</code> 向上移动元素
    <code>list[pos], list[pos+1], &middot;&middot;&middot;, list[#list]</code>。
    <code>pos</code> 的默认值为 <code>#list+1</code>, 因此调用 <code>table.insert(t,x)</code> 将在列表 <code>t</code> 的末尾插入 <code>x</code>。

    <p />
    <hr />
    <h3><a name="pdf-table.move"><code>table.move (a1, f, e, t [,a2])</code></a></h3>

    <p />
    将元素从表 <code>a1</code> 移动到表 <code>a2</code>, 执行等价于下面的多个赋值:
    <code>a2[t],&middot;&middot;&middot; = a1[f],&middot;&middot;&middot;,a1[e]</code>。
    <code>a2</code> 的默认值为 <code>a1</code>。
    目标范围可以与原范围重叠。
    需要移动的元素数量必须为 Lua 整数。

    <p />
    返回目标表 <code>a2</code>。

    <p />
    <hr />
    <h3><a name="pdf-table.pack"><code>table.pack (&middot;&middot;&middot;)</code></a></h3>

    <p />
    返回一个新表，将所有参数存储在建 1, 2, 等等。
    并具有一个名为 "<code>n</code>" 的字段，其中包含总参数数量。
    注意，如果某些参数为 <b>nil</b>，则结果表可能不是序列。

    <p />
    <hr />
    <h3><a name="pdf-table.remove"><code>table.remove (list [, pos])</code></a></h3>

    <p />
    从 <code>list</code> 中移除在位置 <code>pos</code> 处的元素, 返回被移除元素的值。
    当 <code>pos</code> 为一个在 1 和 <code>#list</code> 之间的数字时，他会向下顺移元素
    <code>list[pos+1], list[pos+2], &middot;&middot;&middot;, list[#list]</code> 并擦除元素 <code>list[#list]</code>;
    索引 <code>pos</code> 可以是 <code>#list + 1</code>，当 <code>#list</code> 为 0 时，它也可以是 0。

    <p />
    <code>pos</code> 默认为 <code>#list</code>, 因此调用 <code>table.remove(l)</code> 将移除列表 <code>l</code> 的最后一个元素。

    <p />
    <hr />
    <h3><a name="pdf-table.sort"><code>table.sort (list [, comp])</code></a></h3>

    <p />
    按给定顺序在 <em>in-place(原地)</em> 对 <code>list[1]</code> 到 <code>list[#list]</code> 之间的元素进行排序。
    如果给定了 <code>comp</code>, 他必须是一个函数，这个函数接收两个列表元素并且在最终顺序中第一个元素必须在第二个元素之前时返回 true。
    也就是，排序后 <code>i &lt;= j</code> 意味着 <code>not comp(list[j],list[i])</code>。
    如果没有给定 <code>comp</code>, 使用标准 Lua 操作符 <code>&lt;</code>。

    <p />
    <code>comp</code> 函数必须定义一个明确的顺序; 更正式地说，函数必须定义一个严格的弱序(类似于总序，但它可以将不同的元素等同起来进行比较)。

    <p />
    排序算法并不稳定；因此当两个元素次序相等时，它们在排序后的相对位置可能会改变。

    <p />
    <hr />
    <h3><a name="pdf-table.unpack"><code>table.unpack (list [, i [, j]])</code></a></h3>

    <p />
    返回给定列表的元素。
    函数等价于：

    <pre>
     return list[i], list[i+1], &middot;&middot;&middot;, list[j]
</pre>
    <p />
    默认, <code>i</code> 为 1， <code>j</code> 为 <code>#list</code>。

    <h2>6.7 &ndash; <a name="6.7">数学函数库</a></h2>

    <p />
    该库提供基础数学函数。
    它的所有函数都在表 <a name="pdf-math"><code>math</code></a> 中提供。
    具有注释 "<code>整数/浮点数</code>" 的函数在参数为整数时返回整数，为非整数时返回浮点数。
    当返回值在整数范围内时，舍入函数 <a href="#pdf-math.ceil"><code>math.ceil</code></a>, <a href="#pdf-math.floor"><code>math.floor</code></a>
    和 <a href="#pdf-math.modf"><code>math.modf</code></a> 返回一个整数，否则返回浮点数。

    <p />
    <hr />
    <h3><a name="pdf-math.abs"><code>math.abs (x)</code></a></h3>

    <p />
    返回 <code>x</code> 和 <code>-x</code> 之间的最大值。 (整数/浮点数)

    <p />
    <hr />
    <h3><a name="pdf-math.acos"><code>math.acos (x)</code></a></h3>

    <p />
    返回 <code>x</code> (以弧度表示) 的反余弦值。

    <p />
    <hr />
    <h3><a name="pdf-math.asin"><code>math.asin (x)</code></a></h3>

    <p />
    返回 <code>x</code> (以弧度表示) 的反正弦值。

    <p />
    <hr />
    <h3><a name="pdf-math.atan"><code>math.atan (y [, x])</code></a></h3>

    <p />
    返回 <code>y/x</code> (以弧度表示) 的反正切值，
    使用两个参数来找到返回值的象限。
    也会正确处理 <code>x</code> 为 0 的情况。

    <p />
    <code>x</code> 默认为 1,
    因此调用 <code>math.atan(y)</code> 返回返回 <code>y</code> 的反正切值.

    <p />
    <hr />
    <h3><a name="pdf-math.ceil"><code>math.ceil (x)</code></a></h3>

    <p />
    返回大于或等于 <code>x</code> 的最小整数。

    <p />
    <hr />
    <h3><a name="pdf-math.cos"><code>math.cos (x)</code></a></h3>

    <p />
    返回 <code>x</code> (假定以弧度表示) 的余弦值。

    <p />
    <hr />
    <h3><a name="pdf-math.deg"><code>math.deg (x)</code></a></h3>

    <p />
    将弧度 <code>x</code> 由转换为角度。

    <p />
    <hr />
    <h3><a name="pdf-math.exp"><code>math.exp (x)</code></a></h3>

    <p />
    返回值 <em>e<sup>x</sup></em>
    (<code>e</code> 为自然对数的底)。

    <p />
    <hr />
    <h3><a name="pdf-math.floor"><code>math.floor (x)</code></a></h3>

    <p />
    返回小于等于 <code>x</code> 的最大整数。

    <p />
    <hr />
    <h3><a name="pdf-math.fmod"><code>math.fmod (x, y)</code></a></h3>

    <p />
    返回 <code>x</code> 除以 <code>y</code> 圆整后的余数(整数或浮点数)。

    <p />
    <hr />
    <h3><a name="pdf-math.huge"><code>math.huge</code></a></h3>

    <p />
    一个大于所有数字的浮点数 <code>HUGE_VAL</code> 的值。

    <p />
    <hr />
    <h3><a name="pdf-math.log"><code>math.log (x [, base])</code></a></h3>

    <p />
    返回给定底的 <code>x</code> 的对数。
    <code>base</code> 默认为 <em>e</em>
    (即函数返回 <code>x</code> 的自然对数)。

    <p />
    <hr />
    <h3><a name="pdf-math.max"><code>math.max (x, &middot;&middot;&middot;)</code></a></h3>

    <p />
    根据 Lua 操作符 <code>&lt;</code> 返回参数中的最大值。

    <p />
    <hr />
    <h3><a name="pdf-math.maxinteger"><code>math.maxinteger</code></a></h3>
    整数的最大值。

    <p />
    <hr />
    <h3><a name="pdf-math.min"><code>math.min (x, &middot;&middot;&middot;)</code></a></h3>

    <p />
    根据 Lua 操作符 <code>&lt;</code> 返回参数中的最小值。

    <p />
    <hr />
    <h3><a name="pdf-math.mininteger"><code>math.mininteger</code></a></h3>
    整数的最小值。

    <p />
    <hr />
    <h3><a name="pdf-math.modf"><code>math.modf (x)</code></a></h3>

    <p />
    返回 <code>x</code> 的整数部分和小数部分。
    第二个返回值总是浮点数。

    <p />
    <hr />
    <h3><a name="pdf-math.pi"><code>math.pi</code></a></h3>

    <p />
    <em>&pi;</em> 的值。

    <p />
    <hr />
    <h3><a name="pdf-math.rad"><code>math.rad (x)</code></a></h3>

    <p />
    将角度 <code>x</code> 转换为弧度。

    <p />
    <hr />
    <h3><a name="pdf-math.random"><code>math.random ([m [, n]])</code></a></h3>

    <p />
    不带参数调用时，返回一个 <em>[0,1)</em> 区间内均匀分布的伪随机浮点数。
    使用 <code>m</code> 和 <code>n</code> 调用是, <code>math.random</code> 返回一个在 <em>[m, n]</em> 区间内均匀分布的伪随机整数。
    使用正数 <code>n</code> 调用 <code>math.random(n)</code>，它等价于 <code>math.random(1,n)</code>。
    调用 <code>math.random(0)</code> 产生一个所有位都(伪)随机的整数。

    <p />
    这个函数使用 <code>xoshiro256**</code> 算法生成为64位伪随机整数，这些整数都是参数为 0 时的调用结果。
    其他结果 (范围和浮点数) 从这些整数中无区别提取。

    <p />
    Lua 使用与没有参数的 <a href="#pdf-math.randomseed"><code>math.randomseed</code></a> 等价的调用来初始化它的伪随机生成器。
    因此，<code>math.random</code> 应该在每次程序运行时生成不同的结果序列。

    <p />
    <hr />
    <h3><a name="pdf-math.randomseed"><code>math.randomseed ([x [, y]])</code></a></h3>

    <p />
    使用至少一个参数调用时，整数参数 <code>x</code> 和 <code>y</code> 将合并为一个128位的 <em>seed(种子)</em>, 该种子用于重新初始化伪随机生成器;
    相等的种子将产生相同的数字序列。
    <code>y</code> 默认为 0。

    <p />
    不带参数调用时，Lua 生成一个带有弱随机性的种子。

    <p />
    该函数返回实际使用的两个种子组件，因此再次设置它们将重复该序列。

    <p />
    要确保所需的初始化状态的随机性(或相反，要确定序列，例如在调试时)，你应该使用显式参数调用 <a href="#pdf-math.randomseed"><code>math.randomseed</code></a>。

    <p />
    <hr />
    <h3><a name="pdf-math.sin"><code>math.sin (x)</code></a></h3>

    <p />
    返回 <code>x</code>(以弧度表示) 的正弦值。

    <p />
    <hr />
    <h3><a name="pdf-math.sqrt"><code>math.sqrt (x)</code></a></h3>

    <p />
    返回 <code>x</code> 的平方根。
    (你可以使用表达式 <code>x^0.5</code> 计算这个值)

    <p />
    <hr />
    <h3><a name="pdf-math.tan"><code>math.tan (x)</code></a></h3>

    <p />
    返回 <code>x</code> (以弧度表示) 的正切值。

    <p />
    <hr />
    <h3><a name="pdf-math.tointeger"><code>math.tointeger (x)</code></a></h3>

    <p />
    如果 <code>x</code> 可以转换为一个整数，返回该整数，
    否则返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-math.type"><code>math.type (x)</code></a></h3>

    <p />
    如果 <code>x</code> 是一个整数则返回 "<code>integer</code>", 如果他是一个浮点数则返回 "<code>float</code>"，
    如果 <code>x</code> 不是一个数字则返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-math.ult"><code>math.ult (m, n)</code></a></h3>

    <p />
    返回一个布尔值，当且仅当整数将他们作为无符号整数进行比较时 <code>m</code> 小于整数 <code>n</code> 时返回 <b>true</b>。

    <h2>6.8 &ndash; <a name="6.8">输入输出库</a></h2>

    <p />
    I/O(输入输出) 库提供了两种不同的文件操作风格。
    第一种使用隐式文件句柄;
    也就是说，设置要默认输入文件和默认输出文件，并且所有的输入/输出操作都在这些默认文件上进行。
    第二种使用显式文件句柄。

    <p />
    当使用隐式文件句柄时, 所有操作由表 <a name="pdf-io"><code>io</code></a> 提供。
    当使用显式文件句柄时, <a href="#pdf-io.open"><code>io.open</code></a> 操作返回一个文件句柄并且所有作为该文件句柄的方法提供。

    <p />
    文件句柄的元表提供 <code>__gc</code> 和 <code>__close</code> 元方法，被调用时他们尝试关闭文件。

    <p />
    表 <code>io</code> 也提供三个和 C 中含义相同的预定义的文件句柄：
    <a name="pdf-io.stdin"><code>io.stdin</code></a>, <a name="pdf-io.stdout"><code>io.stdout</code></a> 和 <a name="pdf-io.stderr"><code>io.stderr</code></a>。
    I/O 库不会关闭这些文件。

    <p />
    除非另有说明，所有 I/O 函数在失败时返回 <b>fail</b> 加上一个错误消息(第二个返回值)和一个系统相关的错误码(第三个返回值)，成功时返回一个非假值。
    在非 POSIX 系统中，发生错误时错误消息和错误码的计算可能不是线程安全的，因为他们依赖全局 C 变量 <code>errno</code>。

    <p />
    <hr />
    <h3><a name="pdf-io.close"><code>io.close ([file])</code></a></h3>

    <p />
    等价于 <code>file:close()</code>。没有 <code>file</code> 参数时关闭默认输出文件。

    <p />
    <hr />
    <h3><a name="pdf-io.flush"><code>io.flush ()</code></a></h3>

    <p />
    等价于 <code>io.output():flush()</code>。

    <p />
    <hr />
    <h3><a name="pdf-io.input"><code>io.input ([file])</code></a></h3>

    <p />
    使用一个文件名调用时, 打开对应文件名的文件(通过文本模式), 并设置它的句柄为默认输入文件。
    使用一个文件句柄调用时, 简单地把这个文件句柄作为默认输入文件。
    不带参数调用时，返回当前默认输入文件。

    <p />
    函数发生错误时抛出错误，而不是返回一个错误码。

    <p />
    <hr />
    <h3><a name="pdf-io.lines"><code>io.lines ([filename, &middot;&middot;&middot;])</code></a></h3>

    <p />
    以读模式打开给定文件并返回一个迭代函数，该函数和在打开的文件上调用 <code>file:lines(&middot;&middot;&middot;)</code> 得到的迭代器一样。
    当迭代器函数读取值失败时，会自动关闭该文件。
    除了迭代器函数, <code>io.lines</code> 还返回三个其他值: 两个 <b>nil</b> 值作为占位符，加上创建的文件句柄。
    因此, 当使用通用 <b>for</b> 循环时, 如果循环因为错误或 <b>break</b> 被中断时，文件将被关闭。

    <p />
    调用 <code>io.lines()</code> (不带文件名)等价于 <code>io.input():lines("l")</code>;
    也就是说，对默认输入文件的行进行迭代。
    这种情况，迭代器不会在循环结束后关闭文件。

    <p />
    如果打开文件时出错，函数抛出错误，而不是返回错误码。

    <p />
    <hr />
    <h3><a name="pdf-io.open"><code>io.open (filename [, mode])</code></a></h3>

    <p />
    函数以字符串 <code>mode</code> 指定的模式打开文件。
    成功时返回新的文件句柄。

    <p />
    <code>mode</code> 字符串可以是下面中的任一值:

    <ul>
        <li><b>"<code>r</code>": </b> 读模式 (默认值);</li>
        <li><b>"<code>w</code>": </b> 写模式;</li>
        <li><b>"<code>a</code>": </b> 追加模式;</li>
        <li><b>"<code>r+</code>": </b> 更新模式, 之前的数据被保留;</li>
        <li><b>"<code>w+</code>": </b> 更新模式, 之前的数据都被擦除;</li>
        <li><b>"<code>a+</code>": </b> 追加更新模式, 之前的数据被保留,只能在文件末尾写入。</li>
    </ul>
    <p />
    <code>mode</code> 字符串还可以在末尾包含一个 '<code>b</code>', 这表示某些系统上需要以二进制模式打开文件。

    <p />
    <hr />
    <h3><a name="pdf-io.output"><code>io.output ([file])</code></a></h3>

    <p />
    与 <a href="#pdf-io.input"><code>io.input</code></a> 类似但是操作在默认输出文件上。

    <p />
    <hr />
    <h3><a name="pdf-io.popen"><code>io.popen (prog [, mode])</code></a></h3>

    <p />
    函数依赖于系统，并非在所有平台上可见。

    <p />
    启动分离程序 <code>prog</code> 并返回一个文件句柄，你可以使用它从程序中读取数据(如果 <code>mode</code> 为 <code>"r"</code>， 默认值)或向这个程序中写入数据(如果 <code>mode</code> 为 <code>"w"</code>)。

    <p />
    <hr />
    <h3><a name="pdf-io.read"><code>io.read (&middot;&middot;&middot;)</code></a></h3>

    <p />
    等价于 <code>io.input():read(&middot;&middot;&middot;)</code>。

    <p />
    <hr />
    <h3><a name="pdf-io.tmpfile"><code>io.tmpfile ()</code></a></h3>

    <p />
    如果成功则返回一个临时文件的句柄。
    文件在更新模式中打开在程序结束时自动删除。

    <p />
    <hr />
    <h3><a name="pdf-io.type"><code>io.type (obj)</code></a></h3>

    <p />
    检测 <code>obj</code> 是否是一个有效的文件句柄。
    如果 <code>obj</code> 是一个打开的文件句柄，返回字符串 <code>"file"</code>，
    如果 <code>obj</code> 是一个关闭的文件句柄，返回字符串 <code>"closed file"</code>，
    如果 <code>obj</code> 不是一个文件句柄，返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-io.write"><code>io.write (&middot;&middot;&middot;)</code></a></h3>

    <p />
    等价于 <code>io.output():write(&middot;&middot;&middot;)</code>。

    <p />
    <hr />
    <h3><a name="pdf-file:close"><code>file:close ()</code></a></h3>

    <p />
    关闭 <code>file</code>。
    注意，文件句柄被垃圾收集时会被自动关闭，但是这个时间不可预测。

    <p />
    当关闭一个通过 <a href="#pdf-io.popen"><code>io.popen</code></a> 创建的文件句柄时,
    <a href="#pdf-file:close"><code>file:close</code></a> 的返回值和 <a href="#pdf-os.execute"><code>os.execute</code></a>
    一样。

    <p />
    <hr />
    <h3><a name="pdf-file:flush"><code>file:flush ()</code></a></h3>

    <p />
    保存所有写入 <code>file</code> 的数据。

    <p />
    <hr />
    <h3><a name="pdf-file:lines"><code>file:lines (&middot;&middot;&middot;)</code></a></h3>

    <p />
    返回一个迭代器函数，每次调用该函数时，根据给定格式读取文件。
    没有给定格式时，默认使用 "<code>l</code>"。
    举个例子

    <pre>
     for c in file:lines(1) do <em>body</em> end
</pre>
    <p />
    将从当前位置开始遍历文件的所有字符。
    与 <a href="#pdf-io.lines"><code>io.lines</code></a> 不同, 函数不会在循环结束时关闭文件。

    <p />
    <hr />
    <h3><a name="pdf-file:read"><code>file:read (&middot;&middot;&middot;)</code></a></h3>

    <p />
    根据给定格式读取文件 <code>file</code>。
    对于每种格式，函数返回读取的字符对应的字符串或数字，如果不能通过指定格式读取数据则返回 <b>fail</b>。
    (在最后一种情况中，函数不会读取之后的格式)
    当不带参数调用时，他默认读取下一行(见下文)。

    <p />
    可用格式有

    <ul>
        <li><b>"<code>n</code>": </b>
            根据 Lua 的词法规则，读取一个数字并将其作为浮点数或整数返回(数字可能有前导空格和一个符号)。
            该格式总是读取一个尽可能长的输入序列;
            如果该前缀不能形成有效的数字 (例如, 一个空串, "<code>0x</code>" 或 "<code>3.4e-</code>")
            或太长 (超过 200 字符), 将被丢弃并且该格式返回 <b>fail</b>。
        </li>

        <li><b>"<code>a</code>": </b>
            从当前位置开始读取整个文件。
            在文件末尾，返回一个空串：
            该格式不会失败。
        </li>

        <li><b>"<code>l</code>": </b>
            读取跳过行尾的下一行，在文件末尾返回 <b>fail</b>。
            这是默认格式。
        </li>

        <li><b>"<code>L</code>": </b>
            读取保留行尾字符的下一行(如果存在)，
            在文件末尾返回 <b>fail</b>。
        </li>

        <li><b><em>number</em>: </b>
            读取一个不超过该数量字节的字符串，在文件末尾返回 <b>fail</b>。
            如果 <code>number</code> 为 0，不会读取并返回空串，在文件末尾返回 <b>fail</b>。
        </li>

    </ul>
    <p />
    格式 "<code>l</code>" 和 "<code>L</code>" 应该只用于文本文件。

    <p />
    <hr />
    <h3><a name="pdf-file:seek"><code>file:seek ([whence [, offset]])</code></a></h3>

    <p />
    设置并获取文件位置，
    设置及获取基于文件开头处计算出的位置。 设置的位置由 <code>offset</code> 和 <code>whence</code> 字符串 whence 指定的基点决定。基点可以是：
    如下:

    <ul>
        <li><b>"<code>set</code>": </b> 基点为 0(文件开头);</li>
        <li><b>"<code>cur</code>": </b> 基点为当前位置;</li>
        <li><b>"<code>end</code>": </b> 基点为文件尾;</li>
    </ul>
    <p />
    如果成功, <code>seek</code> 返回以字节为单位，从文件开头开始测量的最终文件位置。
    如果 <code>seek</code> 失败, 返回 <b>fail</b> 加上一个描述错误的字符串。

    <p />
    <code>whence</code> 默认为 <code>"cur"</code>， <code>offset</code> 默认为 0。
    因此, 调用 <code>file:seek()</code> 返回当前文件位置，不会修改它。
    调用 <code>file:seek("set")</code> 设置位置到文件开头 (并返回 0);
    调用 <code>file:seek("end")</code> 设置位置到文件末尾，并返回它的大小。

    <p />
    <hr />
    <h3><a name="pdf-file:setvbuf"><code>file:setvbuf (mode [, size])</code></a></h3>

    <p />
    设置文件的缓冲模式。
    有三种可用模式

    <ul>
        <li><b>"<code>no</code>": </b> 不缓冲。</li>
        <li><b>"<code>full</code>": </b> 完全缓冲。</li>
        <li><b>"<code>line</code>": </b> 行缓冲。</li>
    </ul>

    <p />
    对于后两种模式，<code>size</code> 以字节为单位指定缓冲的大小。
    默认会有一个恰当的大小。

    <p />
    每种模式的具体行为都是不可移植的;
    查看你平台中底层 ISO C 函数 <code>setvbuf</code> 以了解更多细节。

    <p />
    <hr />
    <h3><a name="pdf-file:write"><code>file:write (&middot;&middot;&middot;)</code></a></h3>

    <p />
    将每个参数的值写入 <code>file</code>。
    参数必须是字符串或数字。

    <p />
    成功时，函数返回 <code>file</code>。

    <h2>6.9 &ndash; <a name="6.9">操作系统工具</a></h2>

    <p />
    该库通过表 <a name="pdf-os"><code>os</code></a> 提供。

    <p />
    <hr />
    <h3><a name="pdf-os.clock"><code>os.clock ()</code></a></h3>

    <p />
    返回由底层 ISO C 函数 <code>clock</code> 返回的程序使用的 CPU 秒数的粗略估计值。

    <p />
    <hr />
    <h3><a name="pdf-os.date"><code>os.date ([format [, time]])</code></a></h3>

    <p />
    根据给定字符串 <code>format</code> 格式返回一个包含日期和时间信息的表或字符串。

    <p />
    如果有 <code>time</code> 参数, 格式化这个时间(参见 <a href="#pdf-os.time"><code>os.time</code></a> 函数)。
    否则, <code>date</code> 格式化当前时间。

    <p />
    如果 <code>format</code> 以 '<code>!</code>' 开始, 日期格式为协调世时。
    在这个可选字符后, 如果 <code>format</code> 是字符串 "<code>*t</code>", <code>date</code> 返回一个包含下面字段的表:
    <code>year</code>, <code>month</code> (1&ndash;12), <code>day</code> (1&ndash;31),
    <code>hour</code> (0&ndash;23), <code>min</code> (0&ndash;59),
    <code>sec</code> (0&ndash;61),
    <code>wday</code> (星期几, 1&ndash;7, 星期天是&nbsp;1),
    <code>yday</code> (一年的第几天, 1&ndash;366) 和 <code>isdst</code> (夏令时标识，一个布尔值)。
    最后一个字段如果不可用则会被缺省。

    <p />
    如果 <code>format</code> 不是 "<code>*t</code>", <code>date</code> 作为字符串返回日期。
    格式使用和 ISO&nbsp;C 函数 <code>strftime</code> 相同的规则。

    <p />
    如果 <code>format</code> 缺省, 默认为 "<code>%c</code>", 它使用当前区域提供人类可读的日期和时间表示。

    <p />
    在非 POSIX 系统中, 函数可能不是线程安全的，因为他的依赖于 C 函数 <code>gmtime</code> 和 <code>localtime</code>。

    <p />
    <hr />
    <h3><a name="pdf-os.difftime"><code>os.difftime (t2, t1)</code></a></h3>

    <p />
    以秒为单位，返回时间 <code>t1</code> 至 <code>t2</code>(由 <a href="#pdf-os.time"><code>os.time</code></a> 返回的值) 的时间差。
    在 POSIX, Windows 和一些其他系统中，这个值等于 <code>t2</code><em>-</em><code>t1</code>。

    <p />
    <hr />
    <h3><a name="pdf-os.execute"><code>os.execute ([command])</code></a></h3>

    <p />
    此函数等价于 ISO C 函数 <code>system</code>。
    他通过 <code>command</code> 执行一个操作系统 shell。
    如果命令成功运行完毕，第一个返回值为 <b>true</b>，否则为 <b>fail</b>。
    第一个返回值后返回一个字符串加上一个数字，
    如下：

    <ul>
        <li><b>"<code>exit</code>": </b>
            命令正常退出；
            接下来的数字是命令退出状态码。
        </li>

        <li><b>"<code>signal</code>": </b>
            命令通过信号结束;
            接下来的数字是结束命令的信号。
        </li>
    </ul>

    <p />
    不带 <code>command</code> 调用时, <code>os.execute</code> 返回一个表示 shell 是否可用的的布尔值。

    <p />
    <hr />
    <h3><a name="pdf-os.exit"><code>os.exit ([code [, close]])</code></a></h3>

    <p />
    调用 ISO C 函数 <code>exit</code> 以结束宿主程序。
    如果 <code>code</code> 是 <b>true</b>, 返回状态为 <code>EXIT_SUCCESS</code>。
    如果 <code>code</code> 是 <b>false</b>, 返回状态为 <code>EXIT_FAILURE</code>。
    如果 <code>code</code> 是一个数字, 返回状态为一个数字。
    <code>code</code> 默认值为 <b>true</b>。

    <p />
    如果第二个可选参数 <code>close</code> 为真, 函数退出前关闭 Lua 状态机 (参见 <a href="#lua_close"><code>lua_close</code></a>)。

    <p />
    <hr />
    <h3><a name="pdf-os.getenv"><code>os.getenv (varname)</code></a></h3>

    <p />
    返回进程环境变量 <code>varname</code> 的值。如果变量未定义则返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-os.remove"><code>os.remove (filename)</code></a></h3>

    <p />
    删除给定文件 (在 POSIX 系统中可以是一个空文件夹)。
    如果函数失败, 返回 <b>fail</b> 加上一个描述错误的字符串和错误码。
    否则返回 true。

    <p />
    <hr />
    <h3><a name="pdf-os.rename"><code>os.rename (oldname, newname)</code></a></h3>

    <p />
    重命名名为 <code>oldname</code> 的文件或文件夹为 <code>newname</code>。
    如果函数失败，返回 <b>fail</b> 加上一个描述错误的字符串和错误码。
    否则返回 true。

    <p />
    <hr />
    <h3><a name="pdf-os.setlocale"><code>os.setlocale (locale [, category])</code></a></h3>

    <p />
    设置程序的当前区域。
    <code>locale</code> 是一个指定区域的系统相关字符串；
    <code>category</code> 是一个描述要更改的类别的字符串：
    <code>"all"</code>, <code>"collate"</code>, <code>"ctype"</code>,
    <code>"monetary"</code>, <code>"numeric"</code> 或 <code>"time"</code>;
    默认类别为 <code>"all"</code>。
    函数返回新区域的名字，或请求失败时返回 <b>fail</b>。

    <p />
    如果 <code>locale</code> 是一个字符串, 当前区域被设置为一个在实现中定义好的本地区域。
    如果 <code>locale</code> 是字符串 "<code>C</code>"，当前区域被设置为标准 C 区域。

    <p />
    当第一个参数为 <b>nil</b> 时，函数仅返回当前区域指定分类的名字。

    <p />
    由于这个函数依赖 C 函数 <code>setlocale</code>，它可能并非线程安全的。

    <p />
    <hr />
    <h3><a name="pdf-os.time"><code>os.time ([table])</code></a></h3>

    <p />
    不带参数调用时返回当前时间，给定表时返回一个表示本地日期时间的时间。
    这个表必须有字段 <code>year</code>, <code>month</code>, and <code>day</code>，
    可能有 <code>hour</code> (默认为 12), <code>min</code> (默认为 0), <code>sec</code> (默认 0) 和 <code>isdst</code> (默认为 <b>nil</b>)。
    其他字段将被忽略。关于这些字段的描述, 参见 <a href="#pdf-os.date"><code>os.date</code></a> 函数。

    <p />
    调用函数时, 这些字段的值不需要再其有效范围内。
    例如, 如果 <code>sec</code> 是 -10, 这意味着其他字段指定的时间的 10 秒之前;
    如果 <code>hour</code> 是 1000, 这意味着其他字段指定的时间的 1000 小时后。

    <p />
    返回值是一个数字，它的含义由你的系统决定。在 POSIX, Windows 和一些其他系统中, 这个数字统计了从指定时间("epoch")开始经历的秒数。
    在其他系统中，其含义未定， <code>time</code> 返回的数字只能作为 <a href="#pdf-os.date"><code>os.date</code></a> 和 <a href="#pdf-os.difftime"><code>os.difftime</code></a> 的参数。

    <p />
    使用一个表调用时, <code>os.time</code> 也会规范化 <a href="#pdf-os.date"><code>os.date</code></a> 函数中的所有字段,
    以便他们表示与调用前相同的时间，他们的值在有效范围内。

    <p />
    <hr />
    <h3><a name="pdf-os.tmpname"><code>os.tmpname ()</code></a></h3>

    <p />
    返回可以用于临时文件名的字符串。
    该文件必须在使用前显式打开并在不再使用时显示删除。

    <p />
    在 POSIX 系统中, 这个函数也会通过该名字创建一个文件，以避免安全风险(其他人可能在获取名字和创建文件之间的时间创建文件)。
    您仍然需要打开文件才能使用它并删除它(即是你没有使用它)。

    <p />
    如果可能, 你更应该使用 <a href="#pdf-io.tmpfile"><code>io.tmpfile</code></a>，它会在程序结束时自动移除该文件。

    <h2>6.10 &ndash; <a name="6.10">调试库</a></h2>

    <p />
    该库提供了 Lua 程序调试接口 (<a href="#4.7">&sect;4.7</a>) 功能。
    使用这个库时，你应该额外小心。
    其中一些函数违反了关于 Lua 代码的基本假设(例如, 函数的局部变量不能在外部访问；用户数据的元表不能通过 Lua 代码来修改；Lua 程序不会崩溃)，
    因此可能会对其他安全代码产生危害。
    此外，这个库中的一些函数可能很慢。

    <p />
    这个库中的所有函数在 <a name="pdf-debug"><code>debug</code></a> 表中提供。
    操作线程的所有函数都有一个可选的第一参数，他表示需要操作的线程，默认总是当前线程。

    <p />
    <hr />
    <h3><a name="pdf-debug.debug"><code>debug.debug ()</code></a></h3>

    <p />
    进入用户交互模式，运行用户输入的每个字符串。
    使用简单的命令和其他调试工具，用户可以检查全局变量和局部变量，改变它们的值，计算表达式等等。
    一行只包含单词 <code>cont</code> 的行会结束这个函数，使得调用者继续它的执行。

    <p />
    注意，<code>debug.debug</code> 的命令不会在任何函数内部进行词法嵌套，因此无法直接访问局部变量。

    <p />
    <hr />
    <h3><a name="pdf-debug.gethook"><code>debug.gethook ([thread])</code></a></h3>

    <p />
    返回线程当前的钩子设置，他们作为三个值：当前钩子函数，当前钩子掩码和当前钩子计数，他们由 <a href="#pdf-debug.sethook"><code>debug.sethook</code></a> 设置。

    <p />
    如果没有活动的钩子，返回 <b>fail</b>。

    <p />
    <hr />
    <h3><a name="pdf-debug.getinfo"><code>debug.getinfo ([thread,] f [, what])</code></a></h3>

    <p />
    返回一个包含表相关信息的表。
    你可以直接给出函数，也可以将 <code>f</code> 的值设置为一个数字，这个数字意味着给定线程中的第 <code>f</code> 层级调用的函数：
    层级 0 为当前函数(<code>getinfo</code> 自身);
    层级 1 是调用 <code>getinfo</code> 的函数(除非是尾调用，这些调用不在栈中计数);依此类推。
    如果 <code>f</code> 是大于活动函数的数量的数字，那么 <code>getinfo</code> 返回 <b>fail</b>。

    <p />
    返回的表可以包含 <a href="#lua_getinfo"><code>lua_getinfo</code></a> 返回的所有字段, 字符串 <code>what</code> 描述了需要填充的字段。
    <code>what</code> 默认为获取除有效行的表外所有可用信息。
    如果存在选项 '<code>f</code>' 添加一个包含函数自身的名为 <code>func</code> 的字段。
    如果存在选项 '<code>L</code>' 添加一个包含有效行的表名为 <code>activelines</code> 的字段。

    <p />
    例如，表达式 <code>debug.getinfo(1,"n").name</code> 在能找到合理函数名时返回当前函数名，
    表达式 <code>debug.getinfo(print)</code> 一个包含关于 <a href="#pdf-print"><code>print</code></a> 函数的所有可用信息的表。

    <p />
    <hr />
    <h3><a name="pdf-debug.getlocal"><code>debug.getlocal ([thread,] f, local)</code></a></h3>

    <p />
    该函数返回栈中第 <code>f</code> 级函数中索引为 <code>local</code> 的局部变量的名称和值。
    该函数不仅会访问显式局部变量，还会访问参数和临时值。

    <p />
    第一个参数或局部变量索引为 1, 以此类推，按照他们在代码中声明的顺序，尽对函数当前作用域内活动的变量进行计数。
    编译时常量可能由于编译器优化而不再该列表中。
    负数索引表示可变参数；-1 是第一个可变参数。
    如果给定索引的变量不存在，则函数返回 <b>fail</b>，并在超出范围的层级上调用时抛出错误(你可以调用 <a href="#pdf-debug.getinfo"><code>debug.getinfo</code></a> 以检查层级是否有效)。

    <p />
    以 '<code>(</code>' (开括号) 开头的变量名表示没有已知名称的变量(例如循环控制变量以及未保存调试信息的变量)。

    <p />
    参数 <code>f</code> 可以是一个函数。在这种情况下, <code>getlocal</code> 只返回函数参数的名称。

    <p />
    <hr />
    <h3><a name="pdf-debug.getmetatable"><code>debug.getmetatable (value)</code></a></h3>

    <p />
    返回 <code>value</code> 的元表，如果它没有元表则返回 <b>nil</b>。

    <p />
    <hr />
    <h3><a name="pdf-debug.getregistry"><code>debug.getregistry ()</code></a></h3>

    <p />
    返回注册表(参见 <a href="#4.3">&sect;4.3</a>)。

    <p />
    <hr />
    <h3><a name="pdf-debug.getupvalue"><code>debug.getupvalue (f, up)</code></a></h3>

    <p />
    函数返回函数 <code>f</code> 中索引为 <code>up</code> 的上值的名字和值。
    如果没有给定索引的上值返回 <b>fail</b>。

    <p />
    (对于 Lua 函数, 上值是函数使用的外部局部变量，并因此包含在函数的闭包中)

    <p />
    对于 C 函数, 这个函数使用空串 <code>""</code> 作为所有上值的名字。

    <p />
    变量名 '<code>?</code>' (问号) 表示没有已知名字的变量(没有保存调试信息的代码块中获取的变量)。

    <p />
    <hr />
    <h3><a name="pdf-debug.getuservalue"><code>debug.getuservalue (u, n)</code></a></h3>

    <p />
    返回第 <code>n</code> 个与用户数据 <code>u</code> 相关联的用户值加上一个布尔值, 如果用户数据没有该值则返回 <b>false</b>。

    <p />
    <hr />
    <h3><a name="pdf-debug.sethook"><code>debug.sethook ([thread,] hook, mask [, count])</code></a></h3>

    <p />
    将给定函数作为调试钩子函数。
    字符串 <code>mask</code> 和数字 <code>count</code> 描述钩子何时被调用。
    字符串 <code>mask</code> 可以是下面字符的任意组合，
    他们的含义是：

    <ul>
        <li><b>'<code>c</code>': </b> 钩子在每当 Lua 调用一个函数时被调用；</li>
        <li><b>'<code>r</code>': </b> 钩子在每当 Lua 从一个函数返回时被调用；</li>
        <li><b>'<code>l</code>': </b> 钩子在每当 Lua 进入一行新的代码时调用一个函数时被调用。</li>
    </ul>
    <p />
    此外, 如果 <code>count</code> 不为 0, 每次调用 <code>count</code> 指令后也会调用该钩子。

    <p />
    不带参数调用时, <a href="#pdf-debug.sethook"><code>debug.sethook</code></a> 关闭钩子。

    <p />
    当钩子被调用时, 他的第一个参数是一个描述触发事件的字符串：
    <code>"call"(函数调用)</code>, <code>"tail call"(尾调用)</code>, <code>"return"(函数返回)</code>,
    <code>"line"(行)</code> 和 <code>"count"(计数)</code>。
    对于行事件, 钩子也会获取新行数作为它的第二个参数。
    在钩子中，你可以使用层级 2 调用 <code>getinfo</code> 以获取更多关于正在运行的函数的信息。
    (层级 0 为 <code>getinfo</code> 函数, 层级 1 为钩子函数)

    <p />
    <hr />
    <h3><a name="pdf-debug.setlocal"><code>debug.setlocal ([thread,] level, local, value)</code></a></h3>

    <p />
    函数将 栈中第 <code>level</code> 层函数中索引为 <code>local</code> 的局部变量赋值为 <code>value</code>。
    给定索引的局部变量不存在时返回 <b>fail</b>, <code>level</code> 超出范围时抛出错误(可以调用 <code>getinfo</code> 以检测层级是否有效)，
    否则返回该局部变量的名字。

    <p />
    参见 <a href="#pdf-debug.getlocal"><code>debug.getlocal</code></a> 了解关于变量索引和名字的更多信息。

    <p />
    <hr />
    <h3><a name="pdf-debug.setmetatable"><code>debug.setmetatable (value, table)</code></a></h3>

    <p />
    设置给定值 <code>value</code> 的元表为 <code>table</code>(可以为 <b>nil</b>)。
    返回 <code>value</code>。

    <p />
    <hr />
    <h3><a name="pdf-debug.setupvalue"><code>debug.setupvalue (f, up, value)</code></a></h3>

    <p />
    函数将函数 <code>f</code> 的索引为 <code>up</code> 的上值赋值为 <code>value</code>。
    如果没有给定索引的上值，函数返回 <b>fail</b>。
    否则返回该上值的名字。

    <p />
    参见 <a href="#pdf-debug.getupvalue"><code>debug.getupvalue</code></a> 了解关于上值的更多信息。

    <p />
    <hr />
    <h3><a name="pdf-debug.setuservalue"><code>debug.setuservalue (udata, value, n)</code></a></h3>

    <p />
    设置与给定 <code>udata</code> 的第 <code>n</code> 个用户值赋值为 <code>value</code>。
    <code>udata</code> 必须是一个完全用户数据。

    <p />
    如果用户数据没有该值则返回 <b>fail</b>，否则返回 <code>udata</code>。

    <p />
    <hr />
    <h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message [, level]])</code></a></h3>

    <p />
    如果 <code>message</code> 存在，但既不是字符串也不是 <b>nil</b>, 函数直接返回 <code>message</code>。
    否则, 它返回一个表示调用堆栈回溯信息的字符串。
    选项字符串 <code>message</code> 将被添加到回溯信息的开头。
    选项数字 <code>level</code> 告知开始回溯堆栈的层级(默认为 1, 调用 <code>traceback</code> 的函数)。

    <p />
    <hr />
    <h3><a name="pdf-debug.upvalueid"><code>debug.upvalueid (f, n)</code></a></h3>

    <p />
    返回一个给定函数的编码为 <code>n</code> 的上值的唯一标识(作为一个轻量用户数据)。

    <p />
    这些唯一标识允许程序检测不同闭包中是否共享上值。
    共享上值的 Lua 闭包(即, 引用了相同的外部局部变量)将为这些上值索引返回完全相同的标识。

    <p />
    <hr />
    <h3><a name="pdf-debug.upvaluejoin"><code>debug.upvaluejoin (f1, n1, f2, n2)</code></a></h3>

    <p />
    将 Lua 闭包 <code>f1</code> 的第 <code>n1</code> 个上值指向 Lua 闭包 <code>f2</code> 的第 <code>n2</code> 个上值。

    <h1>7 &ndash; <a name="7">独立版 Lua</a></h1>

    <p />
    尽管 Lua 被设计为一种用于嵌入宿主 C 程序的扩展语言，但它也经常作为独立语言使用。
    标准发行版中提供了一种用于独立语言的 Lua 解释器，称为 <code>lua</code>。
    独立解释器包含所有标准库，其用法为：

    <pre>
     lua [options] [script [args]]
</pre>
    <p />
    选项有：

    <ul>
        <li><b><code>-e <em>stat</em></code>: </b> 执行字符串 <em>stat</em>;</li>
        <li><b><code>-i</code>: </b> 执行 <em>script</em> 后进入交互模式;</li>
        <li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> 并将结果赋值到全局 <em>mod</em>;</li>
        <li><b><code>-l <em>g=mod</em></code>: </b> "require" <em>mod</em> 并将结果赋值到全局 <em>g</em>;</li>
        <li><b><code>-v</code>: </b> 打印版本信息;</li>
        <li><b><code>-E</code>: </b> 忽略环境变量;</li>
        <li><b><code>-W</code>: </b> 打开警告;</li>
        <li><b><code>--</code>: </b> 停止处理选项;</li>
        <li><b><code>-</code>: </b> 将 <code>stdin</code> 作为文件执行并停止处理选项。</li>
    </ul>
    <p />
    (格式 <code>-l <em>g=mod</em></code> 在 5.4.4 中引入。)

    <p />
    处理完这些选项后, <code>lua</code> 运行给定 <em>script</em>。
    不带参数调用时, 当标准输入(<code>stdin</code>)是一个终端时, <code>lua</code> 表现为 <code>lua -v -i</code>，否则表现为 <code>lua -</code>。

    <p />
    带选项 <code>-E</code> 调用时, 解释器运行任何其他参数前会检测环境变量 <a name="pdf-LUA_INIT_5_4"><code>LUA_INIT_5_4</code></a>
    (如果版本名未定义则为 <a name="pdf-LUA_INIT"><code>LUA_INIT</code></a>)。
    如果变量内容格式为 <code>@<em>filename</em></code>, <code>lua</code> 执行该文件。
    否则, <code>lua</code> 执行字符串本身。

    <p />
    当使用选项 <code>-E</code> 调用时,lua 不会查询任何环境变量。
    特别地, <a href="#pdf-package.path"><code>package.path</code></a> 和 <a href="#pdf-package.cpath"><code>package.cpath</code></a> 的值设置为 <code>luaconf.h</code> 中定义的默认路径。

    <p />
    选项 <code>-e</code>, <code>-l</code> 和 <code>-W</code> 按照他们出现的顺序进行处理。
    例如，一个这样的调用

    <pre>
     $ lua -e 'a=1' -llib1 script.lua
</pre>
    <p />
    将先设置 <code>a</code> 为 1, 然后请求库 <code>lib1</code>,
    最后不带参数运行文件 <code>script.lua</code>(这儿的 <code>$</code> 是 shell 提示符。你的提示符可能不同)。

    <p />
    运行任何代码前, <code>lua</code> 将所有命令行参数收集到一个称为 <code>arg</code> 的全局表中。
    脚本名放在索引 0 上，第一个脚本名称后的参数放在索引 1，等等。
    所有脚本名前的参数 (即, 解释器名称加上它的选项) 放在负索引中。
    例如，调用

    <pre>
     $ lua -la b.lua t1 t2
</pre>
    <p />
    该表如下:

    <pre>
     arg = { [-2] = "lua ", [-1] = "-la",
             [0] = "b.lua ",
             [1] = "t1", [2] = "t2" }
</pre>
    <p />
    如果没有脚本在调用中，解释器名称位于索引 0 处，后面是其他参数。
    例如，调用

    <pre>
     $ lua -e "print(arg[1])"
</pre>
    <p />
    将打印 "<code>-e</code>"。
    如果有脚本，脚本调用参数为 <code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>。
    和所有 Lua 中的代码块一样, 脚本编译为一个可变参数函数。

    <p />
    在交互模式下，Lua 不断提示并等待输入一行。
    读取一行后， Lua 首先尝试将该行解释为表达式。
    如果成功，打印它的结果。
    否则，它将该行解释为语句。
    如果你写了一个不完整的语句，解释器通过显示不同的提示符以等待语句完整。

    <p />
    如果全局变量 <a name="pdf-_PROMPT"><code>_PROMPT</code></a> 包含一个字符串，其值将作为提示符。
    类似的, 如果全局变量 <a name="pdf-_PROMPT2"><code>_PROMPT2</code></a> 包含一个字符串, 其值作为次要提示符(在不完整语句期间发出)。

    <p />
    在脚本中发生未受保护的错误时，解释器将错误报告给标准错误输出流。
    如果错误对象不是一个字符串但是有元方法 <code>__tostring</code>，解释器调用该元方法来生成最终的消息。
    否则，解释器将错误对象转换为字符串，并将其添加到堆栈回溯中。
    当警告打开时，它们只是简单的被打印到标准错误输出。

    <p />
    当正常完成时, 解释器关闭它的主 Lua 状态机 (参见 <a href="#lua_close"><code>lua_close</code></a>)。
    脚本可以通过调用 <a href="#pdf-os.exit"><code>os.exit</code></a> 来终止，以避免此步骤。

    <p />
    在 Unix 系统中，允许将 lua 用作脚本解释器。
    lua 跳过文件代码块以 <code>#</code> 开头的第一行。
    通过使用 <code>chmod +x</code> 和 <code>#!</code> 形式，可以将 Lua 脚本制作成可执行程序，
    如下所示

    <pre>
     #!/usr/local/bin/lua
</pre>
    <p />
    当然, Lua 解释器的位置可能和你的机器不同。
    如果 <code>lua</code> 在你的 <code>PATH</code> 中,

    <pre>
     #!/usr/bin/env lua
</pre>
    <p />
    是更适当的写法。

    <h1>8 &ndash; <a name="8">与之前版本的不兼容</a></h1>

    <p />
    这里我们列出了从 Lua 5.3 迁移到 Lua 5.4 时可能会遇到的不兼容之处。

    <p />
    可以通过使用适当的选项编译 Lua 来避免某些不兼容之处(参见文件 <code>luaconf.h</code>)。
    然后，所有的这些兼容选项都会在未来被移除。
    通常，这些兼容性选项被移除时，会出现兼容性问题。
    因此，每当你有机会时，都应该尝试使用关闭所有兼容性选项的 Lua 版本来测试你的代码。
    这将简化 Lua 的新版本转换过程。

    <p />
    Lua 的版本更替总是会修改一些 C API 并涉及源代码的修改。例如一些常量的数字值，用宏来实现一些函数。
    因此，你不应该假定二进制在不同 Lua 版本之间是兼容的。
    使用新版本时总是重新编译 Lua API 的客户端。

    <p />
    同样, Lua 版本更改还会改变预编译代码块的内部表现；
    预编译代码块在不同版本中不兼容。

    <p />
    官方发布版的标准路径也可能随版本变化。

    <h2>8.1 &ndash; <a name="8.1">语言的不兼容性</a></h2>
    <ul>
        <li>
            在算术和按位操作中，字符串转为数字的强制转换已从语言核心中删除。
            字符串库使用字符串元方法为算术(但不是位)操作执行类似的工作。
            但是，与以前的版本不同，新实现保留了字符串中数字的隐式类型。
            例如，<code>"1" + "2"</code> 的结果现在是整数，而不是浮点数。
        </li>

        <li>
            溢出的十进制整数字面量被读取为浮点数，而不是发生回绕。
            如果想要旧的行为(将它们作为回绕的整数读取)，则可以使用十六进制表示法。
        </li>

        <li>
            使用 <code>__lt</code> 元方法来模拟 <code>__le</code> 的功能被移除。
            如果需要，必须显式定义这个元方法。
        </li>

        <li>
            数字 <b>for</b> 循环语义的一些细节变化。
            特别地，控制变量不会发生回绕。
        </li>

        <li>
            在一个有相同名称的可用标签的地方不能将其声明为 <b>goto</b> 标签，即是这个标签在一个嵌套的块中声明的。
        </li>

        <li>
            当终结一个对象时， Lua 不会忽略不是函数 <code>__gc</code> 元方法。
            所有值在存在时都会被调用(不可调用值将生成一个警告，和调用一个终结器时的其他错误一样)。
        </li>
    </ul>

    <h2>8.2 &ndash; <a name="8.2">库的不兼容</a></h2>
    <ul>
        <li>
            函数 <a href="#pdf-print"><code>print</code></a> 不会调用 <a href="#pdf-tostring"><code>tostring</code></a>
            去格式化它的参数。
            取而代之的是，它具有这种功能。
            你应该使用 <code>__tostring</code> 去修改值的打印方式。
        </li>

        <li>
            用于函数 <a href="#pdf-math.random"><code>math.random</code></a> 的伪随机数生成器现在使用一个稍微随机的种子来初始化。
            此外，它使用不同的算法。
        </li>

        <li>
            默认情况下, <a href="#pdf-utf8"><code>utf8</code></a> 库的解码函数不接受 surrogates 作为有效码点。
            这些函数中的额外参数使他们更宽松。
        </li>

        <li>
            函数 <a href="#pdf-collectgarbage"><code>collectgarbage</code></a> 的选项 "<code>setpause</code>" 和
            "<code>setstepmul</code>" 被弃用。
            你应该使用新选项 "<code>incremental</code>" 以设置他们。
        </li>

        <li>
            函数 <a href="#pdf-io.lines"><code>io.lines</code></a> 现在返回四个值，而不是一个。
            当它作为另一个有可选参数的函数(如 <code>load(io.lines(filename, "L"))</code>)的唯一参数时，可能会产生问题。
            要解决该问题，可以将调用括在括号中，以调整其结果数量为一个。
        </li>
    </ul>

    <h2>8.3 &ndash; <a name="8.3">API 的不兼容</a></h2>

    <ul>
        <li>
            完全用户数据现在可以拥有任意数量的关联用户值。
            因此, 函数 <code>lua_newuserdata</code>, <code>lua_setuservalue</code>, 和 <code>lua_getuservalue</code> 被替换为 <a
                href="#lua_newuserdatauv"><code>lua_newuserdatauv</code></a>,
            <a href="#lua_setiuservalue"><code>lua_setiuservalue</code></a> 和 <a
                href="#lua_getiuservalue"><code>lua_getiuservalue</code></a>
            他们有一个额外参数。

            <p />
            为了兼容性，假设只有一个用户值，旧名称仍然可以作为宏使用。
            然而，注意，没有用户值的用户数据更加高效。
        </li>

        <li>
            函数 <a href="#lua_resume"><code>lua_resume</code></a> 有一个额外参数。
            这个参数返回协程被挂起或返回的栈上值的数量(在之前版本中，这些值是整个栈)。
        </li>

        <li>
            函数 <a href="#lua_version"><code>lua_version</code></a> 返回版本号，而不是版本号的地址。
            Lua 核心应该能够正确处理使用其自己静态副本的同一核心的库，所以没有必要检查他们是否使用相同的地址空间。
        </li>

        <li>
            常量 <code>LUA_ERRGCMM</code> 被移除。
            终结器中的错误不会被传播，取而代之的是，他们会产生警告。
        </li>

        <li>
            函数 <a href="#lua_gc"><code>lua_gc</code></a> 的选项 <code>LUA_GCSETPAUSE</code> 和 <code>LUA_GCSETSTEPMUL</code> 被弃用。
            你应该使用新选项 <code>LUA_GCINC</code> 去设置他们。
        </li>
    </ul>

    <h1>9 &ndash; <a name="9">Lua 的完整语法</a></h1>

    <p />
    这是一份采用扩展 BNF 描述的 Lua 完整语法。
    在扩展 BNF 中，{A} 表示 0 或多个 A，[A] 表示一个可选的 A。
    (操作符优先级，参见 <a href="#3.4.8">&sect;3.4.8</a>； 对于最终符号，名字，数字，字符串的解释，参见 <a href="#3.1">&sect;3.1</a>。)
    <pre>

	chunk ::= block

	block ::= {stat} [retstat]

	stat ::=  &lsquo;<b>;</b>&rsquo; |
		 varlist &lsquo;<b>=</b>&rsquo; explist |
		 functioncall |
		 label |
		 <b>break</b> |
		 <b>goto</b> Name |
		 <b>do</b> block <b>end</b> |
		 <b>while</b> exp <b>do</b> block <b>end</b> |
		 <b>repeat</b> block <b>until</b> exp |
		 <b>if</b> exp <b>then</b> block {<b>elseif</b> exp <b>then</b> block} [<b>else</b> block] <b>end</b> |
		 <b>for</b> Name &lsquo;<b>=</b>&rsquo; exp &lsquo;<b>,</b>&rsquo; exp [&lsquo;<b>,</b>&rsquo; exp] <b>do</b> block <b>end</b> |
		 <b>for</b> namelist <b>in</b> explist <b>do</b> block <b>end</b> |
		 <b>function</b> funcname funcbody |
		 <b>local</b> <b>function</b> Name funcbody |
		 <b>local</b> attnamelist [&lsquo;<b>=</b>&rsquo; explist]

	attnamelist ::=  Name attrib {&lsquo;<b>,</b>&rsquo; Name attrib}

	attrib ::= [&lsquo;<b>&lt;</b>&rsquo; Name &lsquo;<b>&gt;</b>&rsquo;]

	retstat ::= <b>return</b> [explist] [&lsquo;<b>;</b>&rsquo;]

	label ::= &lsquo;<b>::</b>&rsquo; Name &lsquo;<b>::</b>&rsquo;

	funcname ::= Name {&lsquo;<b>.</b>&rsquo; Name} [&lsquo;<b>:</b>&rsquo; Name]

	varlist ::= var {&lsquo;<b>,</b>&rsquo; var}

	var ::=  Name | prefixexp &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; | prefixexp &lsquo;<b>.</b>&rsquo; Name

	namelist ::= Name {&lsquo;<b>,</b>&rsquo; Name}

	explist ::= exp {&lsquo;<b>,</b>&rsquo; exp}

	exp ::=  <b>nil</b> | <b>false</b> | <b>true</b> | Numeral | LiteralString | &lsquo;<b>...</b>&rsquo; | functiondef |
		 prefixexp | tableconstructor | exp binop exp | unop exp

	prefixexp ::= var | functioncall | &lsquo;<b>(</b>&rsquo; exp &lsquo;<b>)</b>&rsquo;

	functioncall ::=  prefixexp args | prefixexp &lsquo;<b>:</b>&rsquo; Name args

	args ::=  &lsquo;<b>(</b>&rsquo; [explist] &lsquo;<b>)</b>&rsquo; | tableconstructor | LiteralString

	functiondef ::= <b>function</b> funcbody

	funcbody ::= &lsquo;<b>(</b>&rsquo; [parlist] &lsquo;<b>)</b>&rsquo; block <b>end</b>

	parlist ::= namelist [&lsquo;<b>,</b>&rsquo; &lsquo;<b>...</b>&rsquo;] | &lsquo;<b>...</b>&rsquo;

	tableconstructor ::= &lsquo;<b>{</b>&rsquo; [fieldlist] &lsquo;<b>}</b>&rsquo;

	fieldlist ::= field {fieldsep field} [fieldsep]

	field ::= &lsquo;<b>[</b>&rsquo; exp &lsquo;<b>]</b>&rsquo; &lsquo;<b>=</b>&rsquo; exp | Name &lsquo;<b>=</b>&rsquo; exp | exp

	fieldsep ::= &lsquo;<b>,</b>&rsquo; | &lsquo;<b>;</b>&rsquo;

	binop ::=  &lsquo;<b>+</b>&rsquo; | &lsquo;<b>-</b>&rsquo; | &lsquo;<b>*</b>&rsquo; | &lsquo;<b>/</b>&rsquo; | &lsquo;<b>//</b>&rsquo; | &lsquo;<b>^</b>&rsquo; | &lsquo;<b>%</b>&rsquo; |
		 &lsquo;<b>&amp;</b>&rsquo; | &lsquo;<b>~</b>&rsquo; | &lsquo;<b>|</b>&rsquo; | &lsquo;<b>&gt;&gt;</b>&rsquo; | &lsquo;<b>&lt;&lt;</b>&rsquo; | &lsquo;<b>..</b>&rsquo; |
		 &lsquo;<b>&lt;</b>&rsquo; | &lsquo;<b>&lt;=</b>&rsquo; | &lsquo;<b>&gt;</b>&rsquo; | &lsquo;<b>&gt;=</b>&rsquo; | &lsquo;<b>==</b>&rsquo; | &lsquo;<b>~=</b>&rsquo; |
		 <b>and</b> | <b>or</b>

	unop ::= &lsquo;<b>-</b>&rsquo; | <b>not</b> | &lsquo;<b>#</b>&rsquo; | &lsquo;<b>~</b>&rsquo;

</pre>

    <p />

    <P CLASS="footer">
        最后更新:
        Tue May 2 20:09:38 UTC 2023
    </P>
    <!--
Last change: revised for Lua 5.4.6
-->

</body>

</html>